@ikon85/agent-workflow-kit 0.36.4 → 0.36.5
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/README.md
CHANGED
|
@@ -445,6 +445,13 @@ the old way. Decision record:
|
|
|
445
445
|
|
|
446
446
|
## Release notes
|
|
447
447
|
|
|
448
|
+
### 0.36.5
|
|
449
|
+
|
|
450
|
+
- changed: `src/lib/updateCandidate.mjs`
|
|
451
|
+
- changed: `src/lib/updateReconcile.mjs`
|
|
452
|
+
- changed: `src/lib/verifyUpdateCandidate.mjs`
|
|
453
|
+
- changed: `src/lib/verifyUpdateCandidateTransaction.mjs`
|
|
454
|
+
|
|
448
455
|
### 0.36.4
|
|
449
456
|
|
|
450
457
|
- changed: `scripts/release-delta-guard.mjs`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.5",
|
|
4
4
|
"description": "Portable AI-agent workflow skills (plan → execute → land → learn) for Claude Code & Codex — grilling, TDD, diagnosis, two-axis code review, cross-model Codex review, design & domain-modeling, plus a skill router (ask-matt). npx init/update/diff/uninstall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -351,6 +351,14 @@ async function assertConsumerStillMatchesPreview(consumerRoot, preview) {
|
|
|
351
351
|
throw new Error(`consumer changed during verification: ${path}`);
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
|
+
for (const snapshot of preview.userModifiedSnapshots ?? []) {
|
|
355
|
+
const target = join(consumerRoot, snapshot.path);
|
|
356
|
+
const current = await exists(target) ? await sha256File(target) : null;
|
|
357
|
+
const mode = current === null ? null : (await lstat(target)).mode & 0o777;
|
|
358
|
+
if (current !== snapshot.sha256 || mode !== snapshot.mode) {
|
|
359
|
+
throw new Error(`consumer changed during verification: ${snapshot.path}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
354
362
|
}
|
|
355
363
|
|
|
356
364
|
/** Seed only newly declared, decision-free project-layer stubs in a staged candidate. */
|
|
@@ -156,6 +156,11 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
|
|
|
156
156
|
} else if (userEdited) {
|
|
157
157
|
nextInstalled.push(withInstallRole(prior));
|
|
158
158
|
result.userModified.push(file.path);
|
|
159
|
+
result.userModifiedSnapshots.push({
|
|
160
|
+
path: file.path,
|
|
161
|
+
sha256: current,
|
|
162
|
+
mode: currentMode,
|
|
163
|
+
});
|
|
159
164
|
} else {
|
|
160
165
|
nextInstalled.push(withInstallRole(prior));
|
|
161
166
|
result.unchanged.push(file.path);
|
|
@@ -202,6 +207,7 @@ export async function reconcile({ kitRoot, consumerRoot, decide = () => false, d
|
|
|
202
207
|
function emptyResult() {
|
|
203
208
|
return {
|
|
204
209
|
unchanged: [], updated: [], conflicts: [], collisions: [], collisionResolutions: [], userModified: [],
|
|
210
|
+
userModifiedSnapshots: [],
|
|
205
211
|
ownershipStates: [],
|
|
206
212
|
bridgeRetired: [],
|
|
207
213
|
added: [], deleted: [], keptDeleted: [], consumerOwned: [], manifestChanged: false,
|
|
@@ -61,11 +61,14 @@ export async function verifyCandidateMetadata(candidateRoot, context) {
|
|
|
61
61
|
if (!state.isFile()) {
|
|
62
62
|
throw new Error(`candidate invariant artifact: not a regular file ${entry.path}`);
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
const localSnapshot = (context.preview.userModifiedSnapshots ?? [])
|
|
65
|
+
.find(({ path }) => path === entry.path);
|
|
66
|
+
const expectedMode = localSnapshot?.mode ?? entry.mode;
|
|
67
|
+
if (tracked.origin === KIT_ORIGIN && (state.mode & 0o777) !== expectedMode) {
|
|
65
68
|
throw new Error(`candidate invariant artifact: mode mismatch ${entry.path}`);
|
|
66
69
|
}
|
|
67
|
-
const expectedHash = tracked.origin === CONSUMER_ORIGIN
|
|
68
|
-
? tracked.installedSha256 : entry.sha256;
|
|
70
|
+
const expectedHash = localSnapshot?.sha256 ?? (tracked.origin === CONSUMER_ORIGIN
|
|
71
|
+
? tracked.installedSha256 : entry.sha256);
|
|
69
72
|
if (await sha256File(join(candidateRoot, entry.path)) !== expectedHash) {
|
|
70
73
|
throw new Error(`candidate invariant artifact: hash mismatch ${entry.path}`);
|
|
71
74
|
}
|
|
@@ -44,7 +44,7 @@ export function verifyTransactionPreview(preview, installable, installed) {
|
|
|
44
44
|
const installablePaths = new Set(installable.map(({ path }) => path));
|
|
45
45
|
const owners = new Map();
|
|
46
46
|
const actionSets = new Map();
|
|
47
|
-
for (const key of ['added', 'updated', 'deleted', 'generated', 'keptDeleted']) {
|
|
47
|
+
for (const key of ['added', 'updated', 'deleted', 'generated', 'keptDeleted', 'userModified']) {
|
|
48
48
|
if (!Array.isArray(preview[key] ?? [])) {
|
|
49
49
|
throw new Error(`candidate invariant transaction: ${key} must be an array`);
|
|
50
50
|
}
|
|
@@ -54,12 +54,34 @@ export function verifyTransactionPreview(preview, installable, installed) {
|
|
|
54
54
|
if (['added', 'updated'].includes(key) && !installablePaths.has(path)) {
|
|
55
55
|
throw new Error(`candidate invariant transaction: unmanaged ${key} path ${path}`);
|
|
56
56
|
}
|
|
57
|
+
if (key === 'userModified' && !installablePaths.has(path)) {
|
|
58
|
+
throw new Error(`candidate invariant transaction: unmanaged userModified path ${path}`);
|
|
59
|
+
}
|
|
57
60
|
if (key === 'deleted' && installablePaths.has(path)) {
|
|
58
61
|
throw new Error(`candidate invariant transaction: deletes current package path ${path}`);
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
actionSets.set(key, local);
|
|
62
65
|
}
|
|
66
|
+
if (!Array.isArray(preview.userModifiedSnapshots ?? [])) {
|
|
67
|
+
throw new Error('candidate invariant transaction: userModifiedSnapshots must be an array');
|
|
68
|
+
}
|
|
69
|
+
const modified = actionSets.get('userModified');
|
|
70
|
+
const snapshots = new Set();
|
|
71
|
+
for (const snapshot of preview.userModifiedSnapshots ?? []) {
|
|
72
|
+
const path = snapshot?.path;
|
|
73
|
+
claimTransactionPath(path, 'userModifiedSnapshots', snapshots);
|
|
74
|
+
if (!modified.has(path)
|
|
75
|
+
|| !HASH.test(snapshot.sha256 ?? '')
|
|
76
|
+
|| !Number.isInteger(snapshot.mode)
|
|
77
|
+
|| snapshot.mode < 0
|
|
78
|
+
|| snapshot.mode > 0o777) {
|
|
79
|
+
throw new Error(`candidate invariant transaction: invalid local snapshot ${path}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (snapshots.size !== modified.size) {
|
|
83
|
+
throw new Error('candidate invariant transaction: missing local snapshot');
|
|
84
|
+
}
|
|
63
85
|
if (!Array.isArray(preview.bridgeRetired ?? [])) {
|
|
64
86
|
throw new Error('candidate invariant transaction: bridgeRetired must be an array');
|
|
65
87
|
}
|