@shrkcrft/generator 0.1.0-alpha.3 → 0.1.0-alpha.30
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/dry-run.d.ts.map +1 -1
- package/dist/dry-run.js +28 -8
- package/dist/file-change.d.ts +1 -1
- package/dist/file-change.d.ts.map +1 -1
- package/dist/folder-apply.d.ts.map +1 -1
- package/dist/folder-apply.js +46 -2
- package/dist/folder-safety.d.ts.map +1 -1
- package/dist/folder-safety.js +11 -0
- package/dist/generator-engine.d.ts.map +1 -1
- package/dist/generator-engine.js +26 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/operations.d.ts +156 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +5 -0
- package/dist/package-delegate-plan.d.ts +54 -0
- package/dist/package-delegate-plan.d.ts.map +1 -0
- package/dist/package-delegate-plan.js +253 -0
- package/dist/planned-change.d.ts +2 -123
- package/dist/planned-change.d.ts.map +1 -1
- package/dist/planned-change.js +104 -0
- 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/dist/synthetic-plan.d.ts.map +1 -1
- package/dist/synthetic-plan.js +89 -18
- package/package.json +6 -6
package/dist/dry-run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dry-run.d.ts","sourceRoot":"","sources":["../src/dry-run.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAW5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,eAAe,CAAC;IACtB,gEAAgE;IAChE,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,aAAa,
|
|
1
|
+
{"version":3,"file":"dry-run.d.ts","sourceRoot":"","sources":["../src/dry-run.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAW5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,eAAe,CAAC;IACtB,gEAAgE;IAChE,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,aAAa,CA8Gf"}
|
package/dist/dry-run.js
CHANGED
|
@@ -30,6 +30,12 @@ export function planGeneration(template, request) {
|
|
|
30
30
|
}
|
|
31
31
|
const rendered = renderTemplate(template, validation.resolved);
|
|
32
32
|
const changes = [];
|
|
33
|
+
// Per-file content overlay so that MULTIPLE changes (or a files() create
|
|
34
|
+
// followed by a changes() op) targeting the SAME file COMPOSE. Without
|
|
35
|
+
// this every change is evaluated against the original on-disk bytes and
|
|
36
|
+
// the writer's last same-file write clobbers the earlier ones. Keyed by
|
|
37
|
+
// absolute path → the cumulative content after the prior change(s).
|
|
38
|
+
const overlay = new Map();
|
|
33
39
|
// 1) Legacy CREATE-only files() output — unchanged behaviour.
|
|
34
40
|
for (const file of rendered.files) {
|
|
35
41
|
let safe;
|
|
@@ -59,14 +65,16 @@ export function planGeneration(template, request) {
|
|
|
59
65
|
// unreadable existing file — treat as conflict
|
|
60
66
|
}
|
|
61
67
|
const decision = decideForExisting(file.overwrite ? OverwriteStrategy.Overwrite : overwriteStrategy, existing, file.content);
|
|
68
|
+
const contents = decision.type === FileChangeType.Skip ? existing : file.content;
|
|
62
69
|
changes.push({
|
|
63
70
|
type: decision.type,
|
|
64
71
|
absolutePath,
|
|
65
72
|
relativePath: relPath,
|
|
66
|
-
contents
|
|
73
|
+
contents,
|
|
67
74
|
reason: decision.reason,
|
|
68
75
|
sizeBytes: Buffer.byteLength(file.content, 'utf8'),
|
|
69
76
|
});
|
|
77
|
+
overlay.set(absolutePath, contents);
|
|
70
78
|
}
|
|
71
79
|
else {
|
|
72
80
|
changes.push({
|
|
@@ -77,11 +85,13 @@ export function planGeneration(template, request) {
|
|
|
77
85
|
reason: 'New file (does not exist)',
|
|
78
86
|
sizeBytes: Buffer.byteLength(file.content, 'utf8'),
|
|
79
87
|
});
|
|
88
|
+
overlay.set(absolutePath, file.content);
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
|
-
// 2) v2 planned changes — evaluate against live filesystem
|
|
91
|
+
// 2) v2 planned changes — evaluate against the live filesystem, threaded
|
|
92
|
+
// through the overlay so successive changes to one file compose.
|
|
83
93
|
for (const tplChange of rendered.changes) {
|
|
84
|
-
const evaluated = planOne(tplChange, request.projectRoot);
|
|
94
|
+
const evaluated = planOne(tplChange, request.projectRoot, overlay);
|
|
85
95
|
changes.push(evaluated);
|
|
86
96
|
}
|
|
87
97
|
const { hasConflicts } = summarizeConflicts(changes);
|
|
@@ -98,7 +108,7 @@ export function planGeneration(template, request) {
|
|
|
98
108
|
safe: !hasConflicts && changes.length > 0,
|
|
99
109
|
};
|
|
100
110
|
}
|
|
101
|
-
function planOne(tplChange, projectRoot) {
|
|
111
|
+
function planOne(tplChange, projectRoot, overlay) {
|
|
102
112
|
const op = tplChange.operation;
|
|
103
113
|
let safe;
|
|
104
114
|
try {
|
|
@@ -121,15 +131,23 @@ function planOne(tplChange, projectRoot) {
|
|
|
121
131
|
targetPath: tplChange.targetPath,
|
|
122
132
|
operation: op,
|
|
123
133
|
};
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
// Prefer the overlay (cumulative result of prior same-file changes) over
|
|
135
|
+
// the on-disk bytes so successive ops on one file compose deterministically.
|
|
136
|
+
const existing = overlay?.has(safe.absolutePath)
|
|
137
|
+
? (overlay.get(safe.absolutePath) ?? null)
|
|
138
|
+
: existsSync(safe.absolutePath)
|
|
139
|
+
? readFileSafe(safe.absolutePath)
|
|
140
|
+
: null;
|
|
141
|
+
const result = evaluatePlannedChange({
|
|
128
142
|
change,
|
|
129
143
|
absolutePath: safe.absolutePath,
|
|
130
144
|
relativePath: safe.relativePath,
|
|
131
145
|
existing,
|
|
132
146
|
});
|
|
147
|
+
// Record the cumulative content (Skip/Conflict carry the unchanged bytes,
|
|
148
|
+
// which is exactly what a later op on the same file should see).
|
|
149
|
+
overlay?.set(safe.absolutePath, result.contents);
|
|
150
|
+
return result;
|
|
133
151
|
}
|
|
134
152
|
function readFileSafe(absolutePath) {
|
|
135
153
|
try {
|
|
@@ -170,6 +188,8 @@ function previewContentForOperation(op) {
|
|
|
170
188
|
return `${op.enumName}.${op.entryName} = '${op.entryValue}'`;
|
|
171
189
|
case 'insert-object-entry':
|
|
172
190
|
return `${op.objectName}.${op.entryKey}: ${op.entryValue}`;
|
|
191
|
+
case 'insert-array-entry':
|
|
192
|
+
return `${op.arrayName} ⟵ ${op.entryValue}`;
|
|
173
193
|
case 'insert-before-closing-brace':
|
|
174
194
|
return op.snippet;
|
|
175
195
|
case 'insert-between-anchors':
|
package/dist/file-change.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-change.d.ts","sourceRoot":"","sources":["../src/file-change.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"file-change.d.ts","sourceRoot":"","sources":["../src/file-change.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,oBAAY,cAAc;IACxB,MAAM,WAAW;IACjB,2EAA2E;IAC3E,MAAM,WAAW;IACjB,yDAAyD;IACzD,MAAM,WAAW;IACjB,0EAA0E;IAC1E,WAAW,iBAAiB;IAC5B,2EAA2E;IAC3E,YAAY,kBAAkB;IAC9B,oDAAoD;IACpD,OAAO,YAAY;IACnB,+DAA+D;IAC/D,MAAM,WAAW;IACjB,iEAAiE;IACjE,YAAY,kBAAkB;IAC9B,4DAA4D;IAC5D,YAAY,kBAAkB;IAC9B,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder-apply.d.ts","sourceRoot":"","sources":["../src/folder-apply.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"folder-apply.d.ts","sourceRoot":"","sources":["../src/folder-apply.ts"],"names":[],"mappings":"AAeA,OAAO,EAAuB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,eAAe,CAAC;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,+BAA+B,CAAC;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AAMD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,SAAS,cAAc,EAAE,EAC9B,OAAO,EAAE,gBAAgB,GACxB,oBAAoB,CAgJtB"}
|
package/dist/folder-apply.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync, renameSync, rmSync } from 'node:fs';
|
|
14
14
|
import * as nodePath from 'node:path';
|
|
15
|
+
import { pathEscapesRootViaSymlink, safeResolveTargetPath } from '@shrkcrft/core';
|
|
15
16
|
import { checkFolderOpSafety, FolderOpSafety } from "./folder-safety.js";
|
|
16
17
|
function resolveAbs(projectRoot, p) {
|
|
17
18
|
return nodePath.isAbsolute(p) ? p : nodePath.resolve(projectRoot, p);
|
|
@@ -60,7 +61,26 @@ export function applyFolderOps(ops, options) {
|
|
|
60
61
|
});
|
|
61
62
|
continue;
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
+
// The rename DESTINATION is never validated by checkFolderOpSafety (which
|
|
65
|
+
// only checks targetPath), and resolveAbs even allows absolute newPaths —
|
|
66
|
+
// so `newPath: '../sibling'` or '/etc/x' would move the folder OUTSIDE the
|
|
67
|
+
// project root. Enforce containment through the same chokepoint as writes.
|
|
68
|
+
let safeNew;
|
|
69
|
+
try {
|
|
70
|
+
safeNew = safeResolveTargetPath(op.newPath, options.projectRoot);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
const pathErr = e;
|
|
74
|
+
rejected.push({
|
|
75
|
+
...baseResult,
|
|
76
|
+
applied: false,
|
|
77
|
+
safety: FolderOpSafety.Unsafe,
|
|
78
|
+
reason: `rename-folder destination "${op.newPath}" is outside the project root (${pathErr.code}).`,
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const safeAbsNewPath = safeNew.absolutePath;
|
|
83
|
+
if (existsSync(safeAbsNewPath)) {
|
|
64
84
|
rejected.push({
|
|
65
85
|
...baseResult,
|
|
66
86
|
applied: false,
|
|
@@ -73,8 +93,19 @@ export function applyFolderOps(ops, options) {
|
|
|
73
93
|
applied.push({ ...baseResult, applied: false });
|
|
74
94
|
continue;
|
|
75
95
|
}
|
|
96
|
+
// Defense in depth: re-verify the SOURCE has not become a symlink that
|
|
97
|
+
// escapes the sandbox between safety-check and mutation (TOCTOU window).
|
|
98
|
+
if (pathEscapesRootViaSymlink(options.projectRoot, absTarget)) {
|
|
99
|
+
rejected.push({
|
|
100
|
+
...baseResult,
|
|
101
|
+
applied: false,
|
|
102
|
+
safety: FolderOpSafety.Unsafe,
|
|
103
|
+
reason: `rename-folder source "${op.targetPath}" resolves outside the project root (symlink escape).`,
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
76
107
|
try {
|
|
77
|
-
renameSync(absTarget,
|
|
108
|
+
renameSync(absTarget, safeAbsNewPath);
|
|
78
109
|
applied.push({ ...baseResult, applied: true });
|
|
79
110
|
}
|
|
80
111
|
catch (e) {
|
|
@@ -93,6 +124,19 @@ export function applyFolderOps(ops, options) {
|
|
|
93
124
|
applied.push({ ...baseResult, applied: false });
|
|
94
125
|
continue;
|
|
95
126
|
}
|
|
127
|
+
// Defense in depth: re-verify the target has not become a symlink that
|
|
128
|
+
// escapes the sandbox before a recursive delete. checkFolderOpSafety
|
|
129
|
+
// already gates this; a second realpath probe closes the TOCTOU window
|
|
130
|
+
// so we never rmSync EXTERNAL data.
|
|
131
|
+
if (pathEscapesRootViaSymlink(options.projectRoot, absTarget)) {
|
|
132
|
+
rejected.push({
|
|
133
|
+
...baseResult,
|
|
134
|
+
applied: false,
|
|
135
|
+
safety: FolderOpSafety.Unsafe,
|
|
136
|
+
reason: `delete-folder target "${op.targetPath}" resolves outside the project root (symlink escape).`,
|
|
137
|
+
});
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
96
140
|
try {
|
|
97
141
|
rmSync(absTarget, { recursive: true, force: false });
|
|
98
142
|
applied.push({ ...baseResult, applied: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder-safety.d.ts","sourceRoot":"","sources":["../src/folder-safety.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"folder-safety.d.ts","sourceRoot":"","sources":["../src/folder-safety.ts"],"names":[],"mappings":"AAgBA,oBAAY,cAAc;IACxB,IAAI,SAAS;IACb,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,eAAe,GAAG,eAAe,EACvC,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GACxC,qBAAqB,CA+DvB"}
|
package/dist/folder-safety.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { existsSync, statSync } from 'node:fs';
|
|
13
13
|
import * as nodePath from 'node:path';
|
|
14
14
|
import * as nodeOs from 'node:os';
|
|
15
|
+
import { pathEscapesRootViaSymlink } from '@shrkcrft/core';
|
|
15
16
|
export var FolderOpSafety;
|
|
16
17
|
(function (FolderOpSafety) {
|
|
17
18
|
FolderOpSafety["Safe"] = "safe";
|
|
@@ -33,6 +34,16 @@ export function checkFolderOpSafety(projectRoot, target, kind, options) {
|
|
|
33
34
|
reason: `Target path "${target}" resolves to "${abs}" which is outside the project root "${normalisedRoot}".`,
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
// Realpath-aware containment — a lexically-clean path can still traverse an
|
|
38
|
+
// in-root symlink (e.g. `linkdir -> ../outside`) so that `linkdir/secret`
|
|
39
|
+
// physically lives outside the sandbox. A destructive rmSync/renameSync on
|
|
40
|
+
// such a path would corrupt EXTERNAL data while reporting success.
|
|
41
|
+
if (pathEscapesRootViaSymlink(normalisedRoot, abs)) {
|
|
42
|
+
return {
|
|
43
|
+
safety: FolderOpSafety.Unsafe,
|
|
44
|
+
reason: `Target path "${target}" resolves to "${abs}" which is outside the project root (symlink escape).`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
36
47
|
if (abs === normalisedRoot) {
|
|
37
48
|
return { safety: FolderOpSafety.Unsafe, reason: 'Target path resolves to the project root.' };
|
|
38
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator-engine.d.ts","sourceRoot":"","sources":["../src/generator-engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;CACjC;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"generator-engine.d.ts","sourceRoot":"","sources":["../src/generator-engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;CACjC;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CA2ErC"}
|
package/dist/generator-engine.js
CHANGED
|
@@ -21,8 +21,15 @@ export function generate(template, request) {
|
|
|
21
21
|
if (plan.hasConflicts) {
|
|
22
22
|
return err(new AppErrorImpl(ERROR_CODES.TARGET_FILE_EXISTS, 'Generation refused: plan has conflicts (use --force / different overwrite strategy)', { details: { conflicts: plan.changes.filter((c) => c.type === FileChangeType.Conflict) } }));
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// Multiple changes can target the SAME path (e.g. create-then-insert). The
|
|
25
|
+
// overlay in planGeneration makes each change's `contents` cumulative, so the
|
|
26
|
+
// LAST writeable change per path already carries the composed result. Write
|
|
27
|
+
// each distinct path once and count written/totalBytes by distinct path —
|
|
28
|
+
// matching the synthetic-plan writer. Writing every change would double-count
|
|
29
|
+
// and re-write the same file. (Single-op-per-path plans, the common case, are
|
|
30
|
+
// unchanged.)
|
|
31
|
+
const lastWriteableByPath = new Map();
|
|
32
|
+
const writeOrder = [];
|
|
26
33
|
let skipped = 0;
|
|
27
34
|
for (const change of plan.changes) {
|
|
28
35
|
if (change.type === FileChangeType.Skip) {
|
|
@@ -30,15 +37,23 @@ export function generate(template, request) {
|
|
|
30
37
|
continue;
|
|
31
38
|
}
|
|
32
39
|
if (isWriteableChange(change.type)) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
if (!lastWriteableByPath.has(change.absolutePath))
|
|
41
|
+
writeOrder.push(change.absolutePath);
|
|
42
|
+
lastWriteableByPath.set(change.absolutePath, change);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const written = [];
|
|
46
|
+
let totalBytes = 0;
|
|
47
|
+
for (const path of writeOrder) {
|
|
48
|
+
const change = lastWriteableByPath.get(path);
|
|
49
|
+
try {
|
|
50
|
+
mkdirSync(dirname(change.absolutePath), { recursive: true });
|
|
51
|
+
writeFileSync(change.absolutePath, change.contents, 'utf8');
|
|
52
|
+
written.push(change);
|
|
53
|
+
totalBytes += change.sizeBytes;
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
return err(new AppErrorImpl(ERROR_CODES.FILE_WRITE_ERROR, `Failed to write ${change.absolutePath}`, { details: { path: change.absolutePath }, cause: e }));
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
59
|
return ok({
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './planned-change.js';
|
|
|
12
12
|
export * from './folder-safety.js';
|
|
13
13
|
export * from './folder-apply.js';
|
|
14
14
|
export * from './synthetic-plan.js';
|
|
15
|
+
export * from './package-delegate-plan.js';
|
|
15
16
|
export * from './spec/index.js';
|
|
16
17
|
export * from './grounding/index.js';
|
|
17
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,5 +12,6 @@ export * from "./planned-change.js";
|
|
|
12
12
|
export * from "./folder-safety.js";
|
|
13
13
|
export * from "./folder-apply.js";
|
|
14
14
|
export * from "./synthetic-plan.js";
|
|
15
|
+
export * from "./package-delegate-plan.js";
|
|
15
16
|
export * from "./spec/index.js";
|
|
16
17
|
export * from "./grounding/index.js";
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operation union — declared by templates, persisted in saved plans.
|
|
3
|
+
* Part of the v2 generation model.
|
|
4
|
+
*/
|
|
5
|
+
export type PlannedOperationKind = 'create' | 'append' | 'insert-after' | 'insert-before' | 'replace' | 'export' | 'ensure-import' | 'insert-enum-entry' | 'insert-object-entry' | 'insert-array-entry' | 'insert-before-closing-brace' | 'insert-between-anchors';
|
|
6
|
+
export interface ICreateOperation {
|
|
7
|
+
kind: 'create';
|
|
8
|
+
content: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface IAppendOperation {
|
|
12
|
+
kind: 'append';
|
|
13
|
+
/**
|
|
14
|
+
* The snippet to append at the end of the file. The engine adds a single
|
|
15
|
+
* `\n` separator between the existing trailing content and the snippet if
|
|
16
|
+
* the existing file does not already end with a newline.
|
|
17
|
+
*/
|
|
18
|
+
snippet: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional idempotency marker. If the existing file already contains this
|
|
21
|
+
* string anywhere, the operation is skipped (already applied).
|
|
22
|
+
*/
|
|
23
|
+
ifMissing?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface IInsertAfterOperation {
|
|
27
|
+
kind: 'insert-after';
|
|
28
|
+
/** Literal substring that must appear exactly once in the file. */
|
|
29
|
+
anchor: string;
|
|
30
|
+
/** The snippet to insert immediately after `anchor`. */
|
|
31
|
+
snippet: string;
|
|
32
|
+
/** Idempotency check; default = `snippet`. */
|
|
33
|
+
ifMissing?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface IInsertBeforeOperation {
|
|
37
|
+
kind: 'insert-before';
|
|
38
|
+
anchor: string;
|
|
39
|
+
snippet: string;
|
|
40
|
+
ifMissing?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface IReplaceOperation {
|
|
44
|
+
kind: 'replace';
|
|
45
|
+
/** Literal substring to find. */
|
|
46
|
+
find: string;
|
|
47
|
+
/** Replacement text. */
|
|
48
|
+
replaceWith: string;
|
|
49
|
+
/**
|
|
50
|
+
* If provided, the engine requires exactly this many matches; otherwise the
|
|
51
|
+
* default is exactly 1. Multiple matches without an explicit `expectMatches`
|
|
52
|
+
* is a conflict (ambiguous replace).
|
|
53
|
+
*/
|
|
54
|
+
expectMatches?: number;
|
|
55
|
+
description?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface IExportOperation {
|
|
58
|
+
kind: 'export';
|
|
59
|
+
/** The symbol/path to re-export. */
|
|
60
|
+
from: string;
|
|
61
|
+
/** Optional named symbols. When omitted, emits `export * from`. */
|
|
62
|
+
symbols?: readonly string[];
|
|
63
|
+
/** Idempotency check; default = computed export line. */
|
|
64
|
+
ifMissing?: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface IEnsureImportOperation {
|
|
68
|
+
kind: 'ensure-import';
|
|
69
|
+
/** Module specifier, e.g. `'./events'` or `'@app/plugin-core'`. */
|
|
70
|
+
from: string;
|
|
71
|
+
/**
|
|
72
|
+
* Named symbols to ensure. The op is a NO-OP for symbols already imported
|
|
73
|
+
* from `from`. Default import (`type: 'default'`) and namespace import
|
|
74
|
+
* (`type: 'namespace'`) are also supported via dedicated fields below.
|
|
75
|
+
*/
|
|
76
|
+
symbols?: readonly string[];
|
|
77
|
+
/** Treat the import as `import type { ... }` instead of value import. */
|
|
78
|
+
typeOnly?: boolean;
|
|
79
|
+
/** Default import binding (e.g. `import Foo from 'foo'`). */
|
|
80
|
+
defaultBinding?: string;
|
|
81
|
+
/** Namespace import binding (e.g. `import * as foo from 'foo'`). */
|
|
82
|
+
namespaceBinding?: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface IInsertEnumEntryOperation {
|
|
86
|
+
kind: 'insert-enum-entry';
|
|
87
|
+
/** Enum identifier, e.g. `PaginationEventType`. */
|
|
88
|
+
enumName: string;
|
|
89
|
+
/** Identifier of the new enum member, e.g. `ITEM_SELECTED`. */
|
|
90
|
+
entryName: string;
|
|
91
|
+
/** Literal string value to assign, e.g. `'pagination.itemSelected'`. */
|
|
92
|
+
entryValue: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface IInsertObjectEntryOperation {
|
|
96
|
+
kind: 'insert-object-entry';
|
|
97
|
+
/** Object identifier, e.g. `ROUTE_KEYS`. */
|
|
98
|
+
objectName: string;
|
|
99
|
+
/** Key to add. */
|
|
100
|
+
entryKey: string;
|
|
101
|
+
/** Value literal (already source-formatted). */
|
|
102
|
+
entryValue: string;
|
|
103
|
+
/** When `true`, allow shorthand entries; default `false`. */
|
|
104
|
+
shorthand?: boolean;
|
|
105
|
+
description?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface IInsertArrayEntryOperation {
|
|
108
|
+
kind: 'insert-array-entry';
|
|
109
|
+
/**
|
|
110
|
+
* Array identifier — a `const`/`let`/`var` bound to an array literal,
|
|
111
|
+
* e.g. `editorScopeEntries` or `DEFAULT_PANELS`. The element is inserted
|
|
112
|
+
* before the array's matching closing bracket.
|
|
113
|
+
*/
|
|
114
|
+
arrayName: string;
|
|
115
|
+
/**
|
|
116
|
+
* Fallback array identifiers tried, in order, when `arrayName` does not
|
|
117
|
+
* resolve in the target project (registration arrays are often named
|
|
118
|
+
* differently across codebases). The first cleanly-resolved candidate
|
|
119
|
+
* wins. When none resolve, the op surfaces an actionable manual-wiring
|
|
120
|
+
* conflict instead of an opaque "array not found".
|
|
121
|
+
*/
|
|
122
|
+
arrayNameAlternatives?: readonly string[];
|
|
123
|
+
/**
|
|
124
|
+
* Precise manual-wiring instruction shown when no candidate array resolves.
|
|
125
|
+
* When set, it replaces the synthesized "wire <entry> into <array> manually"
|
|
126
|
+
* message — letting a template author mark this step as a MANUAL follow-up
|
|
127
|
+
* with exact guidance instead of an opaque conflict.
|
|
128
|
+
*/
|
|
129
|
+
manualStepInstruction?: string;
|
|
130
|
+
/** Element source text to add (already source-formatted, no trailing comma). */
|
|
131
|
+
entryValue: string;
|
|
132
|
+
/** Optional idempotency marker (default = `entryValue`). */
|
|
133
|
+
ifMissing?: string;
|
|
134
|
+
description?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface IInsertBeforeClosingBraceOperation {
|
|
137
|
+
kind: 'insert-before-closing-brace';
|
|
138
|
+
/** Container identifier, e.g. an interface/class/enum name. */
|
|
139
|
+
containerName: string;
|
|
140
|
+
/** Snippet inserted immediately before the matching closing brace. */
|
|
141
|
+
snippet: string;
|
|
142
|
+
/** Optional idempotency marker (default = `snippet`). */
|
|
143
|
+
ifMissing?: string;
|
|
144
|
+
description?: string;
|
|
145
|
+
}
|
|
146
|
+
export interface IInsertBetweenAnchorsOperation {
|
|
147
|
+
kind: 'insert-between-anchors';
|
|
148
|
+
beginAnchor: string;
|
|
149
|
+
endAnchor: string;
|
|
150
|
+
snippet: string;
|
|
151
|
+
/** Optional idempotency marker (default = `snippet`). */
|
|
152
|
+
ifMissing?: string;
|
|
153
|
+
description?: string;
|
|
154
|
+
}
|
|
155
|
+
export type IPlannedOperation = ICreateOperation | IAppendOperation | IInsertAfterOperation | IInsertBeforeOperation | IReplaceOperation | IExportOperation | IEnsureImportOperation | IInsertEnumEntryOperation | IInsertObjectEntryOperation | IInsertArrayEntryOperation | IInsertBeforeClosingBraceOperation | IInsertBetweenAnchorsOperation;
|
|
156
|
+
//# sourceMappingURL=operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package a delegate worker's raw edit into a SIGNED-ready synthetic plan.
|
|
3
|
+
*
|
|
4
|
+
* This is the deterministic chokepoint between a stochastic worker and the
|
|
5
|
+
* write path. It:
|
|
6
|
+
* 1. drops ops whose `kind` is not in the recipe's `allowedOps` (reported,
|
|
7
|
+
* never applied);
|
|
8
|
+
* 2. validates every remaining op's fields against the real operation union —
|
|
9
|
+
* a malformed op refuses the whole package (the worker must retry);
|
|
10
|
+
* 3. evaluates the ops against the live file system via the SAME
|
|
11
|
+
* `evaluateSavedPlanInPlace` apply uses, so anchor-not-found / ambiguous /
|
|
12
|
+
* file-missing all surface as conflicts BEFORE anything is signed;
|
|
13
|
+
* 4. builds an `ISavedPlan` (templateId `__delegate/<recipe>`) the caller
|
|
14
|
+
* signs + applies through the unmodified apply pipeline.
|
|
15
|
+
*
|
|
16
|
+
* No model, no network. The raw-op input type is declared locally so the
|
|
17
|
+
* generator layer carries no dependency on `@shrkcrft/ai`.
|
|
18
|
+
*/
|
|
19
|
+
import { type AppError, type Result } from '@shrkcrft/core';
|
|
20
|
+
import type { IGenerationPlan } from './generation-plan.js';
|
|
21
|
+
import type { ISavedPlan } from './saved-plan.js';
|
|
22
|
+
export declare const DELEGATE_TEMPLATE_PREFIX = "__delegate/";
|
|
23
|
+
/** A raw operation as parsed from a worker (structurally `IDelegateRawOp`). */
|
|
24
|
+
export interface IDelegateOpInput {
|
|
25
|
+
targetPath: string;
|
|
26
|
+
operation: {
|
|
27
|
+
kind: string;
|
|
28
|
+
} & Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
export interface IPackageDelegateInput {
|
|
31
|
+
ops: readonly IDelegateOpInput[];
|
|
32
|
+
/** `IPlannedOperation` kinds the recipe permits; others are dropped. */
|
|
33
|
+
allowedOps: readonly string[];
|
|
34
|
+
/** Recipe id — becomes the synthetic templateId `__delegate/<id>`. */
|
|
35
|
+
recipeId: string;
|
|
36
|
+
projectRoot: string;
|
|
37
|
+
}
|
|
38
|
+
export interface IDroppedOp {
|
|
39
|
+
kind: string;
|
|
40
|
+
targetPath: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
}
|
|
43
|
+
export interface IPackageDelegateResult {
|
|
44
|
+
/** Conflict-free, ready to sign. Present only when `ready`. */
|
|
45
|
+
plan?: ISavedPlan;
|
|
46
|
+
/** The evaluated generation plan (changes + conflicts) — always present. */
|
|
47
|
+
generation: IGenerationPlan;
|
|
48
|
+
/** Ops whose kind was not in `allowedOps`. */
|
|
49
|
+
droppedOps: readonly IDroppedOp[];
|
|
50
|
+
/** True when no conflicts — the plan is built and ready to sign + apply. */
|
|
51
|
+
ready: boolean;
|
|
52
|
+
}
|
|
53
|
+
export declare function packageDelegatePlan(input: IPackageDelegateInput): Result<IPackageDelegateResult, AppError>;
|
|
54
|
+
//# sourceMappingURL=package-delegate-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-delegate-plan.d.ts","sourceRoot":"","sources":["../src/package-delegate-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAsC,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAmBlD,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACjC,wEAAwE;IACxE,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,4EAA4E;IAC5E,UAAU,EAAE,eAAe,CAAC;IAC5B,8CAA8C;IAC9C,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC;IAClC,4EAA4E;IAC5E,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,qBAAqB,GAC3B,MAAM,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAoE1C"}
|