@ikon85/agent-workflow-kit 0.27.0 → 0.27.1
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 +4 -0
- package/agent-workflow-kit.package.json +2 -2
- package/package.json +1 -1
- package/scripts/release-parity.mjs +34 -0
- package/scripts/release-parity.test.mjs +37 -0
- package/src/cli.mjs +5 -2
- package/src/commands/update.mjs +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kitVersion": "0.27.
|
|
2
|
+
"kitVersion": "0.27.1",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".agents/skills/ask-matt/SKILL.md",
|
|
@@ -2539,7 +2539,7 @@
|
|
|
2539
2539
|
"path": "scripts/release-parity.mjs",
|
|
2540
2540
|
"kind": "script",
|
|
2541
2541
|
"installRole": "consumer",
|
|
2542
|
-
"sha256": "
|
|
2542
|
+
"sha256": "32f61bf776974be63a017e90f428d4dab6098a9e2ba0c25c865d18ea3bd3e89e",
|
|
2543
2543
|
"mode": 420,
|
|
2544
2544
|
"origin": "kit"
|
|
2545
2545
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.1",
|
|
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": {
|
|
@@ -50,3 +50,37 @@ export function assertReleaseParity(identities) {
|
|
|
50
50
|
}
|
|
51
51
|
return identities.local;
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
// Consumer-side identity: an unpacked installation cannot be re-packed
|
|
55
|
+
// byte-identically (npm normalizes at publish/unpack), so the installed copy
|
|
56
|
+
// proves itself by content — never by a fresh tarball hash.
|
|
57
|
+
const INSTALLED_FIELDS = ['name', 'version', 'manifestSha256'];
|
|
58
|
+
|
|
59
|
+
export async function installedIdentityFromDir(kitRoot) {
|
|
60
|
+
const packageJson = JSON.parse(await readFile(`${kitRoot}/package.json`, 'utf8'));
|
|
61
|
+
const manifest = await readFile(`${kitRoot}/agent-workflow-kit.package.json`);
|
|
62
|
+
if (packageJson.version !== JSON.parse(manifest).kitVersion) {
|
|
63
|
+
throw new Error('installed package and manifest versions mismatch');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
name: packageJson.name,
|
|
67
|
+
version: packageJson.version,
|
|
68
|
+
manifestSha256: digest('sha256', manifest),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function assertConsumerReleaseParity({ installed, npm, github }) {
|
|
73
|
+
validate('npm', npm);
|
|
74
|
+
validate('github', github);
|
|
75
|
+
for (const field of FIELDS) {
|
|
76
|
+
if (github[field] !== npm[field]) throw new Error(`github ${field} mismatch`);
|
|
77
|
+
}
|
|
78
|
+
if (!installed || typeof installed !== 'object') throw new Error('installed release identity missing');
|
|
79
|
+
for (const field of INSTALLED_FIELDS) {
|
|
80
|
+
if (typeof installed[field] !== 'string' || !installed[field]) {
|
|
81
|
+
throw new Error(`installed ${field} missing`);
|
|
82
|
+
}
|
|
83
|
+
if (installed[field] !== npm[field]) throw new Error(`installed ${field} mismatch`);
|
|
84
|
+
}
|
|
85
|
+
return npm;
|
|
86
|
+
}
|
|
@@ -51,3 +51,40 @@ test('a package tarball produces a deterministic content identity', async () =>
|
|
|
51
51
|
assert.deepEqual(first, second);
|
|
52
52
|
} finally { await rm(root, { recursive: true, force: true }); }
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
test('consumer parity proves npm↔github and matches the installed copy without re-packing', async () => {
|
|
56
|
+
const { assertConsumerReleaseParity } = await import('./release-parity.mjs');
|
|
57
|
+
const installed = { name: identity.name, version: identity.version, manifestSha256: identity.manifestSha256 };
|
|
58
|
+
assert.deepEqual(
|
|
59
|
+
assertConsumerReleaseParity({ installed, npm: { ...identity }, github: { ...identity } }),
|
|
60
|
+
identity,
|
|
61
|
+
);
|
|
62
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
63
|
+
installed, npm: { ...identity }, github: { ...identity, tarballIntegrity: 'different' },
|
|
64
|
+
}), /github tarballIntegrity mismatch/);
|
|
65
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
66
|
+
installed: { ...installed, manifestSha256: 'different' },
|
|
67
|
+
npm: { ...identity }, github: { ...identity },
|
|
68
|
+
}), /installed manifestSha256 mismatch/);
|
|
69
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
70
|
+
installed: { ...installed, version: '9.9.9' },
|
|
71
|
+
npm: { ...identity }, github: { ...identity },
|
|
72
|
+
}), /installed version mismatch/);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('an installed kit directory yields a content identity without npm pack', async () => {
|
|
76
|
+
const { installedIdentityFromDir } = await import('./release-parity.mjs');
|
|
77
|
+
const root = await mkdtemp(join(tmpdir(), 'release-parity-installed-'));
|
|
78
|
+
try {
|
|
79
|
+
const manifest = JSON.stringify({ kitVersion: '1.2.3', files: [] });
|
|
80
|
+
await writeFile(join(root, 'package.json'), JSON.stringify({ name: identity.name, version: '1.2.3' }));
|
|
81
|
+
await writeFile(join(root, 'agent-workflow-kit.package.json'), manifest);
|
|
82
|
+
const installed = await installedIdentityFromDir(root);
|
|
83
|
+
assert.equal(installed.name, identity.name);
|
|
84
|
+
assert.equal(installed.version, '1.2.3');
|
|
85
|
+
assert.equal(typeof installed.manifestSha256, 'string');
|
|
86
|
+
assert.equal('tarballIntegrity' in installed, false);
|
|
87
|
+
} finally {
|
|
88
|
+
await rm(root, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
});
|
package/src/cli.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { update } from './commands/update.mjs';
|
|
|
7
7
|
import { diff } from './commands/diff.mjs';
|
|
8
8
|
import { uninstall } from './commands/uninstall.mjs';
|
|
9
9
|
import { createCommandAdapter } from '../scripts/release-state.mjs';
|
|
10
|
+
import { installedIdentityFromDir } from '../scripts/release-parity.mjs';
|
|
10
11
|
|
|
11
12
|
const KIT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
12
13
|
const consumerRoot = process.cwd();
|
|
@@ -87,8 +88,10 @@ async function readUpdateRelease() {
|
|
|
87
88
|
env: { ...process.env, GH_REPO: 'iKon85/agent-workflow-kit' },
|
|
88
89
|
});
|
|
89
90
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
// Re-packing an unpacked install is never byte-identical to the registry
|
|
92
|
+
// tarball — the installed copy proves itself by content identity instead.
|
|
93
|
+
const installed = await installedIdentityFromDir(KIT_ROOT);
|
|
94
|
+
return { installed, npm: await adapter.npm(installed), github: await adapter.github(installed) };
|
|
92
95
|
} finally {
|
|
93
96
|
await adapter.dispose();
|
|
94
97
|
}
|
package/src/commands/update.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, rm } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { assertConsumerReleaseParity } from '../../scripts/release-parity.mjs';
|
|
4
4
|
import { activateCandidate, stageConsumer, verifyCandidate } from '../lib/updateCandidate.mjs';
|
|
5
5
|
import { reconcile } from '../lib/updateReconcile.mjs';
|
|
6
6
|
import {
|
|
@@ -86,7 +86,7 @@ async function applyTransaction(context) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function verifyRelease(identities, kitVersion) {
|
|
89
|
-
const release =
|
|
89
|
+
const release = assertConsumerReleaseParity(identities);
|
|
90
90
|
if (release.name !== RELEASE_NAME) throw new Error(`invalid release origin: ${release.name}`);
|
|
91
91
|
if (release.version !== kitVersion) {
|
|
92
92
|
throw new Error(`release version ${release.version} does not match kit ${kitVersion}`);
|