instar 0.28.115 → 0.28.117
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/providers/parity/registry.d.ts +23 -0
- package/dist/providers/parity/registry.d.ts.map +1 -0
- package/dist/providers/parity/registry.js +41 -0
- package/dist/providers/parity/registry.js.map +1 -0
- package/dist/providers/parity/rules/hookParityRule.d.ts +34 -0
- package/dist/providers/parity/rules/hookParityRule.d.ts.map +1 -0
- package/dist/providers/parity/rules/hookParityRule.js +463 -0
- package/dist/providers/parity/rules/hookParityRule.js.map +1 -0
- package/dist/providers/parity/rules/skillParityRule.d.ts +47 -0
- package/dist/providers/parity/rules/skillParityRule.d.ts.map +1 -0
- package/dist/providers/parity/rules/skillParityRule.js +618 -0
- package/dist/providers/parity/rules/skillParityRule.js.map +1 -0
- package/dist/providers/parity/types.d.ts +100 -0
- package/dist/providers/parity/types.d.ts.map +1 -0
- package/dist/providers/parity/types.js +13 -0
- package/dist/providers/parity/types.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/0.28.116.md +23 -0
- package/upgrades/0.28.117.md +23 -0
- package/upgrades/side-effects/feat-hook-primitive.md +74 -0
- package/upgrades/side-effects/feat-skill-prototype.md +103 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParityRegistry — registry of all active parity rules.
|
|
3
|
+
*
|
|
4
|
+
* Spec: specs/instar-foundations/framework-functional-parity.md
|
|
5
|
+
* specs/provider-portability/13-framework-parity-sentinel.md
|
|
6
|
+
*
|
|
7
|
+
* Skill prototype shape (this PR): one rule (skillParityRule). Hook, Agent,
|
|
8
|
+
* Tool, Memory primitives add their rules later. The FrameworkParitySentinel
|
|
9
|
+
* (separate spec) consumes this registry to drive its scan + remediate loop.
|
|
10
|
+
*
|
|
11
|
+
* Registry is a plain in-memory map seeded at boot. No persistence needed —
|
|
12
|
+
* rules are code; registration is declarative.
|
|
13
|
+
*/
|
|
14
|
+
import type { ParityRule, FunctionalPrimitive } from './types.js';
|
|
15
|
+
export declare function getParityRule(primitive: FunctionalPrimitive): ParityRule | undefined;
|
|
16
|
+
export declare function listParityRules(): ReadonlyArray<ParityRule>;
|
|
17
|
+
/**
|
|
18
|
+
* Test-only seam — replace the rule for a primitive (used in unit tests to
|
|
19
|
+
* inject mock rules without rebuilding the import graph).
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function _replaceParityRuleForTest(primitive: FunctionalPrimitive, rule: ParityRule): () => void;
|
|
23
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AASlE,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,GAAG,UAAU,GAAG,SAAS,CAEpF;AAED,wBAAgB,eAAe,IAAI,aAAa,CAAC,UAAU,CAAC,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,IAAI,CAOtG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParityRegistry — registry of all active parity rules.
|
|
3
|
+
*
|
|
4
|
+
* Spec: specs/instar-foundations/framework-functional-parity.md
|
|
5
|
+
* specs/provider-portability/13-framework-parity-sentinel.md
|
|
6
|
+
*
|
|
7
|
+
* Skill prototype shape (this PR): one rule (skillParityRule). Hook, Agent,
|
|
8
|
+
* Tool, Memory primitives add their rules later. The FrameworkParitySentinel
|
|
9
|
+
* (separate spec) consumes this registry to drive its scan + remediate loop.
|
|
10
|
+
*
|
|
11
|
+
* Registry is a plain in-memory map seeded at boot. No persistence needed —
|
|
12
|
+
* rules are code; registration is declarative.
|
|
13
|
+
*/
|
|
14
|
+
import { skillParityRule } from './rules/skillParityRule.js';
|
|
15
|
+
import { hookParityRule } from './rules/hookParityRule.js';
|
|
16
|
+
const RULES = new Map([
|
|
17
|
+
[skillParityRule.primitive, skillParityRule],
|
|
18
|
+
[hookParityRule.primitive, hookParityRule],
|
|
19
|
+
]);
|
|
20
|
+
export function getParityRule(primitive) {
|
|
21
|
+
return RULES.get(primitive);
|
|
22
|
+
}
|
|
23
|
+
export function listParityRules() {
|
|
24
|
+
return [...RULES.values()];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Test-only seam — replace the rule for a primitive (used in unit tests to
|
|
28
|
+
* inject mock rules without rebuilding the import graph).
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export function _replaceParityRuleForTest(primitive, rule) {
|
|
32
|
+
const prior = RULES.get(primitive);
|
|
33
|
+
RULES.set(primitive, rule);
|
|
34
|
+
return () => {
|
|
35
|
+
if (prior)
|
|
36
|
+
RULES.set(primitive, prior);
|
|
37
|
+
else
|
|
38
|
+
RULES.delete(primitive);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,MAAM,KAAK,GAAyC,IAAI,GAAG,CAAC;IAC1D,CAAC,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC;IAC5C,CAAC,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,SAA8B;IAC1D,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAA8B,EAAE,IAAgB;IACxF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3B,OAAO,GAAG,EAAE;QACV,IAAI,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;;YAClC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hookParityRule — parity rule for the Hook functional primitive.
|
|
3
|
+
*
|
|
4
|
+
* Specs:
|
|
5
|
+
* - specs/instar-concepts/hook.md (canonical shape + event vocabulary)
|
|
6
|
+
* - specs/frameworks/claude-code/hooks.md
|
|
7
|
+
* - specs/frameworks/codex-cli/hooks.md
|
|
8
|
+
*
|
|
9
|
+
* Reads canonical hooks from `.instar/hooks/<event>/<name>.<ext>` and
|
|
10
|
+
* verifies each framework renders them correctly (script copy + entry in
|
|
11
|
+
* the framework's settings/config file).
|
|
12
|
+
*
|
|
13
|
+
* v0.1 scope: session-start event only. Adding additional events =
|
|
14
|
+
* extending the EVENT_NAME_MAPPING table at the top of the file.
|
|
15
|
+
*
|
|
16
|
+
* Reuses the Skill prototype's hardening patterns:
|
|
17
|
+
* - C1: strict slug grammar at every entry point.
|
|
18
|
+
* - C5: symmetric verify + orphan detection.
|
|
19
|
+
* - C7: x-instar-stamp comment line distinguishes user-edit-conflict
|
|
20
|
+
* from canonical drift; remediate refuses to overwrite conflicts.
|
|
21
|
+
*
|
|
22
|
+
* Deferred to v0.2 (tracked in concept spec):
|
|
23
|
+
* - Events beyond session-start.
|
|
24
|
+
* - Executable-bit verification (currently set on render; not verified).
|
|
25
|
+
* - hooks.json/settings.json merge semantics for non-Instar entries.
|
|
26
|
+
* v0.1 manages only entries whose script paths live under
|
|
27
|
+
* `.claude/hooks/<canonical-event>/` or `.agent/openai/hooks/<canonical-event>/`.
|
|
28
|
+
*/
|
|
29
|
+
import type { ParityRule } from '../types.js';
|
|
30
|
+
export declare class CanonicalHookError extends Error {
|
|
31
|
+
constructor(message: string);
|
|
32
|
+
}
|
|
33
|
+
export declare const hookParityRule: ParityRule;
|
|
34
|
+
//# sourceMappingURL=hookParityRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookParityRule.d.ts","sourceRoot":"","sources":["../../../../src/providers/parity/rules/hookParityRule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,KAAK,EACV,UAAU,EAGX,MAAM,aAAa,CAAC;AAkBrB,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAsZD,eAAO,MAAM,cAAc,EAAE,UA6E5B,CAAC"}
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hookParityRule — parity rule for the Hook functional primitive.
|
|
3
|
+
*
|
|
4
|
+
* Specs:
|
|
5
|
+
* - specs/instar-concepts/hook.md (canonical shape + event vocabulary)
|
|
6
|
+
* - specs/frameworks/claude-code/hooks.md
|
|
7
|
+
* - specs/frameworks/codex-cli/hooks.md
|
|
8
|
+
*
|
|
9
|
+
* Reads canonical hooks from `.instar/hooks/<event>/<name>.<ext>` and
|
|
10
|
+
* verifies each framework renders them correctly (script copy + entry in
|
|
11
|
+
* the framework's settings/config file).
|
|
12
|
+
*
|
|
13
|
+
* v0.1 scope: session-start event only. Adding additional events =
|
|
14
|
+
* extending the EVENT_NAME_MAPPING table at the top of the file.
|
|
15
|
+
*
|
|
16
|
+
* Reuses the Skill prototype's hardening patterns:
|
|
17
|
+
* - C1: strict slug grammar at every entry point.
|
|
18
|
+
* - C5: symmetric verify + orphan detection.
|
|
19
|
+
* - C7: x-instar-stamp comment line distinguishes user-edit-conflict
|
|
20
|
+
* from canonical drift; remediate refuses to overwrite conflicts.
|
|
21
|
+
*
|
|
22
|
+
* Deferred to v0.2 (tracked in concept spec):
|
|
23
|
+
* - Events beyond session-start.
|
|
24
|
+
* - Executable-bit verification (currently set on render; not verified).
|
|
25
|
+
* - hooks.json/settings.json merge semantics for non-Instar entries.
|
|
26
|
+
* v0.1 manages only entries whose script paths live under
|
|
27
|
+
* `.claude/hooks/<canonical-event>/` or `.agent/openai/hooks/<canonical-event>/`.
|
|
28
|
+
*/
|
|
29
|
+
import { promises as fs } from 'node:fs';
|
|
30
|
+
import path from 'node:path';
|
|
31
|
+
import crypto from 'node:crypto';
|
|
32
|
+
const CANONICAL_ROOT = '.instar/hooks';
|
|
33
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
34
|
+
const ALLOWED_EXTS = new Set(['.sh', '.js', '.mjs', '.cjs', '.ts']);
|
|
35
|
+
const STAMP_COMMENT_RE = /^#\s*x-instar-stamp:\s*([a-f0-9]{64})\s*$/m;
|
|
36
|
+
const STAMP_COMMENT_STRIP_RE = /^#\s*x-instar-stamp:\s*[a-f0-9]{64}\s*\r?\n/m;
|
|
37
|
+
const EVENT_NAME_MAPPING = {
|
|
38
|
+
'session-start': { claude: 'SessionStart', codex: 'session_start' },
|
|
39
|
+
};
|
|
40
|
+
const SUPPORTED_EVENTS = Object.keys(EVENT_NAME_MAPPING);
|
|
41
|
+
export class CanonicalHookError extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'CanonicalHookError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function validateSlug(value, context) {
|
|
48
|
+
if (typeof value !== 'string' || !SLUG_RE.test(value)) {
|
|
49
|
+
throw new CanonicalHookError(`${context}: invalid slug "${value}". Must match ${SLUG_RE.source}.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function validateExt(ext, context) {
|
|
53
|
+
if (!ALLOWED_EXTS.has(ext)) {
|
|
54
|
+
throw new CanonicalHookError(`${context}: invalid extension "${ext}". Allowed: ${[...ALLOWED_EXTS].join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function sha256(s) {
|
|
58
|
+
return crypto.createHash('sha256').update(s, 'utf-8').digest('hex');
|
|
59
|
+
}
|
|
60
|
+
function parseInstanceName(instanceName) {
|
|
61
|
+
const slash = instanceName.indexOf('/');
|
|
62
|
+
if (slash < 0) {
|
|
63
|
+
throw new CanonicalHookError(`instanceName "${instanceName}" must be in the form "<event>/<name>.<ext>"`);
|
|
64
|
+
}
|
|
65
|
+
const event = instanceName.slice(0, slash);
|
|
66
|
+
const fileName = instanceName.slice(slash + 1);
|
|
67
|
+
const dot = fileName.lastIndexOf('.');
|
|
68
|
+
if (dot <= 0) {
|
|
69
|
+
throw new CanonicalHookError(`instanceName "${instanceName}" must end with an extension (.sh, .js, .mjs, .cjs, .ts)`);
|
|
70
|
+
}
|
|
71
|
+
const name = fileName.slice(0, dot);
|
|
72
|
+
const ext = fileName.slice(dot);
|
|
73
|
+
return { event, name, ext };
|
|
74
|
+
}
|
|
75
|
+
async function readCanonicalHook(projectRoot, instanceName) {
|
|
76
|
+
const { event, name, ext } = parseInstanceName(instanceName);
|
|
77
|
+
validateSlug(event, 'canonical hook event');
|
|
78
|
+
validateSlug(name, 'canonical hook name');
|
|
79
|
+
validateExt(ext, 'canonical hook extension');
|
|
80
|
+
if (!(event in EVENT_NAME_MAPPING)) {
|
|
81
|
+
throw new CanonicalHookError(`event "${event}" is not in the v0.1 supported set. Supported: ${SUPPORTED_EVENTS.join(', ')}`);
|
|
82
|
+
}
|
|
83
|
+
const scriptPath = path.join(projectRoot, CANONICAL_ROOT, event, `${name}${ext}`);
|
|
84
|
+
let body;
|
|
85
|
+
try {
|
|
86
|
+
body = await fs.readFile(scriptPath, 'utf-8');
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
throw new CanonicalHookError(`canonical hook script missing or unreadable: ${path.relative(projectRoot, scriptPath)} — ${err.message}`);
|
|
90
|
+
}
|
|
91
|
+
// Strip a leading stamp comment from body before hashing so the canonical
|
|
92
|
+
// body hash is stable across rendering cycles.
|
|
93
|
+
const bodyForHash = body.replace(STAMP_COMMENT_STRIP_RE, '');
|
|
94
|
+
return {
|
|
95
|
+
instanceName,
|
|
96
|
+
event: event,
|
|
97
|
+
name,
|
|
98
|
+
ext,
|
|
99
|
+
body: bodyForHash,
|
|
100
|
+
bodyHash: sha256(bodyForHash),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function listCanonicalHookInstances(projectRoot) {
|
|
104
|
+
const root = path.join(projectRoot, CANONICAL_ROOT);
|
|
105
|
+
const out = [];
|
|
106
|
+
let eventDirs;
|
|
107
|
+
try {
|
|
108
|
+
eventDirs = (await fs.readdir(root, { withFileTypes: true }))
|
|
109
|
+
.filter((e) => e.isDirectory() && SLUG_RE.test(e.name))
|
|
110
|
+
.map((e) => e.name);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err.code === 'ENOENT')
|
|
114
|
+
return [];
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
for (const event of eventDirs) {
|
|
118
|
+
if (!(event in EVENT_NAME_MAPPING))
|
|
119
|
+
continue;
|
|
120
|
+
const eventDir = path.join(root, event);
|
|
121
|
+
let files;
|
|
122
|
+
try {
|
|
123
|
+
files = (await fs.readdir(eventDir, { withFileTypes: true })).map((e) => ({
|
|
124
|
+
name: e.name,
|
|
125
|
+
isFile: e.isFile(),
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
for (const f of files) {
|
|
132
|
+
if (!f.isFile)
|
|
133
|
+
continue;
|
|
134
|
+
const dot = f.name.lastIndexOf('.');
|
|
135
|
+
if (dot <= 0)
|
|
136
|
+
continue;
|
|
137
|
+
const baseName = f.name.slice(0, dot);
|
|
138
|
+
const ext = f.name.slice(dot);
|
|
139
|
+
if (!SLUG_RE.test(baseName))
|
|
140
|
+
continue;
|
|
141
|
+
if (!ALLOWED_EXTS.has(ext))
|
|
142
|
+
continue;
|
|
143
|
+
out.push(`${event}/${f.name}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return out.sort();
|
|
147
|
+
}
|
|
148
|
+
function withStamp(body, bodyHash) {
|
|
149
|
+
const stampLine = `# x-instar-stamp: ${bodyHash}\n`;
|
|
150
|
+
// Insert stamp right after a shebang if present, else at the top.
|
|
151
|
+
if (body.startsWith('#!')) {
|
|
152
|
+
const nl = body.indexOf('\n');
|
|
153
|
+
if (nl < 0)
|
|
154
|
+
return body + '\n' + stampLine;
|
|
155
|
+
return body.slice(0, nl + 1) + stampLine + body.slice(nl + 1);
|
|
156
|
+
}
|
|
157
|
+
return stampLine + body;
|
|
158
|
+
}
|
|
159
|
+
function extractStamp(rendered) {
|
|
160
|
+
const m = rendered.match(STAMP_COMMENT_RE);
|
|
161
|
+
return m ? m[1] : null;
|
|
162
|
+
}
|
|
163
|
+
function bodyWithoutStamp(rendered) {
|
|
164
|
+
return rendered.replace(STAMP_COMMENT_STRIP_RE, '');
|
|
165
|
+
}
|
|
166
|
+
function claudeLayout(projectRoot, hook) {
|
|
167
|
+
return {
|
|
168
|
+
scriptPath: path.join(projectRoot, '.claude/hooks', hook.event, `${hook.name}${hook.ext}`),
|
|
169
|
+
configPath: path.join(projectRoot, '.claude/settings.json'),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function codexLayout(projectRoot, hook) {
|
|
173
|
+
return {
|
|
174
|
+
scriptPath: path.join(projectRoot, '.agent/openai/hooks', hook.event, `${hook.name}${hook.ext}`),
|
|
175
|
+
configPath: path.join(projectRoot, '.agent/openai/hooks.json'),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async function readJsonOrDefault(p, def) {
|
|
179
|
+
try {
|
|
180
|
+
const raw = await fs.readFile(p, 'utf-8');
|
|
181
|
+
return JSON.parse(raw);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return def;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function nativeEventForFramework(event, framework) {
|
|
188
|
+
const m = EVENT_NAME_MAPPING[event];
|
|
189
|
+
return framework === 'claude-code' ? m.claude : m.codex;
|
|
190
|
+
}
|
|
191
|
+
async function renderClaudeHook(projectRoot, hook) {
|
|
192
|
+
const layout = claudeLayout(projectRoot, hook);
|
|
193
|
+
await fs.mkdir(path.dirname(layout.scriptPath), { recursive: true });
|
|
194
|
+
await fs.writeFile(layout.scriptPath, withStamp(hook.body, hook.bodyHash), 'utf-8');
|
|
195
|
+
await fs.chmod(layout.scriptPath, 0o755);
|
|
196
|
+
// Merge settings.json hook entry.
|
|
197
|
+
const settings = await readJsonOrDefault(layout.configPath, {});
|
|
198
|
+
const eventKey = nativeEventForFramework(hook.event, 'claude-code');
|
|
199
|
+
const arr = settings.hooks?.[eventKey] ?? [];
|
|
200
|
+
const relScriptPath = path.relative(projectRoot, layout.scriptPath);
|
|
201
|
+
const desiredCommand = `bash ${relScriptPath}`;
|
|
202
|
+
const existing = arr.find((entry) => entry.hooks?.some((h) => h.command === desiredCommand));
|
|
203
|
+
if (!existing) {
|
|
204
|
+
arr.push({
|
|
205
|
+
matcher: '',
|
|
206
|
+
hooks: [{ type: 'command', command: desiredCommand, timeout: 10000 }],
|
|
207
|
+
});
|
|
208
|
+
settings.hooks = { ...(settings.hooks ?? {}), [eventKey]: arr };
|
|
209
|
+
await fs.mkdir(path.dirname(layout.configPath), { recursive: true });
|
|
210
|
+
await fs.writeFile(layout.configPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function renderCodexHook(projectRoot, hook) {
|
|
214
|
+
const layout = codexLayout(projectRoot, hook);
|
|
215
|
+
await fs.mkdir(path.dirname(layout.scriptPath), { recursive: true });
|
|
216
|
+
await fs.writeFile(layout.scriptPath, withStamp(hook.body, hook.bodyHash), 'utf-8');
|
|
217
|
+
await fs.chmod(layout.scriptPath, 0o755);
|
|
218
|
+
await fs.mkdir(path.dirname(layout.configPath), { recursive: true });
|
|
219
|
+
const config = await readJsonOrDefault(layout.configPath, { hooks: [] });
|
|
220
|
+
const eventKey = nativeEventForFramework(hook.event, 'codex-cli');
|
|
221
|
+
const arr = config.hooks ?? [];
|
|
222
|
+
const relScriptPath = path.relative(projectRoot, layout.scriptPath);
|
|
223
|
+
const existing = arr.find((entry) => entry.event === eventKey && entry.script === relScriptPath);
|
|
224
|
+
if (!existing) {
|
|
225
|
+
arr.push({ event: eventKey, script: relScriptPath });
|
|
226
|
+
config.hooks = arr;
|
|
227
|
+
await fs.writeFile(layout.configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async function verifyClaudeHook(projectRoot, hook) {
|
|
231
|
+
const layout = claudeLayout(projectRoot, hook);
|
|
232
|
+
const issues = [];
|
|
233
|
+
let rendered = null;
|
|
234
|
+
try {
|
|
235
|
+
rendered = await fs.readFile(layout.scriptPath, 'utf-8');
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
issues.push({
|
|
239
|
+
reasonCode: 'missing-rendered-file',
|
|
240
|
+
detail: `expected ${path.relative(projectRoot, layout.scriptPath)} to exist`,
|
|
241
|
+
});
|
|
242
|
+
return issues;
|
|
243
|
+
}
|
|
244
|
+
const stamp = extractStamp(rendered);
|
|
245
|
+
const rBody = bodyWithoutStamp(rendered);
|
|
246
|
+
if (rBody !== hook.body) {
|
|
247
|
+
if (stamp && stamp === hook.bodyHash) {
|
|
248
|
+
issues.push({
|
|
249
|
+
reasonCode: 'user-edit-conflict',
|
|
250
|
+
detail: `claude hook script body differs from canonical but stamp matches — user edited the rendering`,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
issues.push({
|
|
255
|
+
reasonCode: 'body-content-mismatch',
|
|
256
|
+
detail: `claude hook script body differs from canonical (stamp ${stamp ? 'stale' : 'missing'})`,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// settings.json entry presence
|
|
261
|
+
const settings = await readJsonOrDefault(layout.configPath, {});
|
|
262
|
+
const eventKey = nativeEventForFramework(hook.event, 'claude-code');
|
|
263
|
+
const arr = settings.hooks?.[eventKey] ?? [];
|
|
264
|
+
const relScriptPath = path.relative(projectRoot, layout.scriptPath);
|
|
265
|
+
const desiredCommand = `bash ${relScriptPath}`;
|
|
266
|
+
const hasEntry = arr.some((entry) => entry.hooks?.some((h) => h.command === desiredCommand));
|
|
267
|
+
if (!hasEntry) {
|
|
268
|
+
issues.push({
|
|
269
|
+
reasonCode: 'sibling-artifact-missing',
|
|
270
|
+
detail: `settings.json missing hook entry for ${eventKey} → ${relScriptPath}`,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return issues;
|
|
274
|
+
}
|
|
275
|
+
async function verifyCodexHook(projectRoot, hook) {
|
|
276
|
+
const layout = codexLayout(projectRoot, hook);
|
|
277
|
+
const issues = [];
|
|
278
|
+
let rendered = null;
|
|
279
|
+
try {
|
|
280
|
+
rendered = await fs.readFile(layout.scriptPath, 'utf-8');
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
issues.push({
|
|
284
|
+
reasonCode: 'missing-rendered-file',
|
|
285
|
+
detail: `expected ${path.relative(projectRoot, layout.scriptPath)} to exist`,
|
|
286
|
+
});
|
|
287
|
+
return issues;
|
|
288
|
+
}
|
|
289
|
+
const stamp = extractStamp(rendered);
|
|
290
|
+
const rBody = bodyWithoutStamp(rendered);
|
|
291
|
+
if (rBody !== hook.body) {
|
|
292
|
+
if (stamp && stamp === hook.bodyHash) {
|
|
293
|
+
issues.push({
|
|
294
|
+
reasonCode: 'user-edit-conflict',
|
|
295
|
+
detail: `codex hook script body differs from canonical but stamp matches — user edited the rendering`,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
issues.push({
|
|
300
|
+
reasonCode: 'body-content-mismatch',
|
|
301
|
+
detail: `codex hook script body differs from canonical (stamp ${stamp ? 'stale' : 'missing'})`,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const config = await readJsonOrDefault(layout.configPath, {});
|
|
306
|
+
const eventKey = nativeEventForFramework(hook.event, 'codex-cli');
|
|
307
|
+
const relScriptPath = path.relative(projectRoot, layout.scriptPath);
|
|
308
|
+
const hasEntry = (config.hooks ?? []).some((entry) => entry.event === eventKey && entry.script === relScriptPath);
|
|
309
|
+
if (!hasEntry) {
|
|
310
|
+
issues.push({
|
|
311
|
+
reasonCode: 'sibling-artifact-missing',
|
|
312
|
+
detail: `hooks.json missing entry for ${eventKey} → ${relScriptPath}`,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return issues;
|
|
316
|
+
}
|
|
317
|
+
// ─── Orphan detection ──────────────────────────────────────────────────
|
|
318
|
+
async function listFrameworkScripts(projectRoot, framework) {
|
|
319
|
+
const root = framework === 'claude-code'
|
|
320
|
+
? path.join(projectRoot, '.claude/hooks')
|
|
321
|
+
: path.join(projectRoot, '.agent/openai/hooks');
|
|
322
|
+
let eventDirs;
|
|
323
|
+
try {
|
|
324
|
+
eventDirs = (await fs.readdir(root, { withFileTypes: true }))
|
|
325
|
+
.filter((e) => e.isDirectory() && SLUG_RE.test(e.name))
|
|
326
|
+
.map((e) => e.name);
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
const out = [];
|
|
332
|
+
for (const event of eventDirs) {
|
|
333
|
+
let files;
|
|
334
|
+
try {
|
|
335
|
+
files = (await fs.readdir(path.join(root, event), { withFileTypes: true })).map((e) => ({
|
|
336
|
+
name: e.name,
|
|
337
|
+
isFile: e.isFile(),
|
|
338
|
+
}));
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
for (const f of files) {
|
|
344
|
+
if (!f.isFile)
|
|
345
|
+
continue;
|
|
346
|
+
const dot = f.name.lastIndexOf('.');
|
|
347
|
+
if (dot <= 0)
|
|
348
|
+
continue;
|
|
349
|
+
const baseName = f.name.slice(0, dot);
|
|
350
|
+
const ext = f.name.slice(dot);
|
|
351
|
+
if (!SLUG_RE.test(baseName))
|
|
352
|
+
continue;
|
|
353
|
+
if (!ALLOWED_EXTS.has(ext))
|
|
354
|
+
continue;
|
|
355
|
+
out.push({ event, name: baseName, ext, fullPath: path.join(root, event, f.name) });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return out;
|
|
359
|
+
}
|
|
360
|
+
async function findOrphans(projectRoot, framework, canonicalInstances) {
|
|
361
|
+
const rendered = await listFrameworkScripts(projectRoot, framework);
|
|
362
|
+
const out = [];
|
|
363
|
+
for (const r of rendered) {
|
|
364
|
+
const instanceName = `${r.event}/${r.name}${r.ext}`;
|
|
365
|
+
if (canonicalInstances.has(instanceName))
|
|
366
|
+
continue;
|
|
367
|
+
out.push({
|
|
368
|
+
primitive: 'hook',
|
|
369
|
+
instanceName,
|
|
370
|
+
framework,
|
|
371
|
+
reasonCode: 'orphan-rendering-found',
|
|
372
|
+
detail: `rendered hook script has no canonical counterpart: ${path.relative(projectRoot, r.fullPath)}`,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return out;
|
|
376
|
+
}
|
|
377
|
+
async function removeOrphanScripts(projectRoot, framework, canonicalInstances) {
|
|
378
|
+
const rendered = await listFrameworkScripts(projectRoot, framework);
|
|
379
|
+
const removed = [];
|
|
380
|
+
for (const r of rendered) {
|
|
381
|
+
const instanceName = `${r.event}/${r.name}${r.ext}`;
|
|
382
|
+
if (canonicalInstances.has(instanceName))
|
|
383
|
+
continue;
|
|
384
|
+
await fs.rm(r.fullPath, { force: true });
|
|
385
|
+
removed.push(r.fullPath);
|
|
386
|
+
}
|
|
387
|
+
return removed;
|
|
388
|
+
}
|
|
389
|
+
// ─── Exported ParityRule ───────────────────────────────────────────────
|
|
390
|
+
export const hookParityRule = {
|
|
391
|
+
primitive: 'hook',
|
|
392
|
+
frameworks: ['claude-code', 'codex-cli'],
|
|
393
|
+
remediationPolicy: 'mirror-trust',
|
|
394
|
+
async listInstances(projectRoot) {
|
|
395
|
+
return listCanonicalHookInstances(projectRoot);
|
|
396
|
+
},
|
|
397
|
+
async verify(projectRoot, instanceName) {
|
|
398
|
+
let hook;
|
|
399
|
+
try {
|
|
400
|
+
hook = await readCanonicalHook(projectRoot, instanceName);
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
return {
|
|
404
|
+
ok: false,
|
|
405
|
+
mismatches: [
|
|
406
|
+
{
|
|
407
|
+
primitive: 'hook',
|
|
408
|
+
instanceName,
|
|
409
|
+
framework: 'canonical',
|
|
410
|
+
reasonCode: 'canonical-read-error',
|
|
411
|
+
detail: err.message,
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const mismatches = [];
|
|
417
|
+
for (const framework of this.frameworks) {
|
|
418
|
+
const issues = framework === 'claude-code'
|
|
419
|
+
? await verifyClaudeHook(projectRoot, hook)
|
|
420
|
+
: await verifyCodexHook(projectRoot, hook);
|
|
421
|
+
for (const issue of issues) {
|
|
422
|
+
mismatches.push({
|
|
423
|
+
primitive: 'hook',
|
|
424
|
+
instanceName,
|
|
425
|
+
framework,
|
|
426
|
+
reasonCode: issue.reasonCode,
|
|
427
|
+
detail: issue.detail,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return { ok: mismatches.length === 0, mismatches };
|
|
432
|
+
},
|
|
433
|
+
async remediate(projectRoot, instanceName, framework) {
|
|
434
|
+
const hook = await readCanonicalHook(projectRoot, instanceName);
|
|
435
|
+
// Refuse on user-edit-conflict.
|
|
436
|
+
const issues = framework === 'claude-code'
|
|
437
|
+
? await verifyClaudeHook(projectRoot, hook)
|
|
438
|
+
: await verifyCodexHook(projectRoot, hook);
|
|
439
|
+
const conflict = issues.find((i) => i.reasonCode === 'user-edit-conflict');
|
|
440
|
+
if (conflict) {
|
|
441
|
+
throw new CanonicalHookError(`refused to remediate ${instanceName} on ${framework} due to user-edit-conflict: ${conflict.detail}`);
|
|
442
|
+
}
|
|
443
|
+
if (framework === 'claude-code') {
|
|
444
|
+
await renderClaudeHook(projectRoot, hook);
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
await renderCodexHook(projectRoot, hook);
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
async listOrphans(projectRoot) {
|
|
451
|
+
const canonical = new Set(await listCanonicalHookInstances(projectRoot));
|
|
452
|
+
const out = [];
|
|
453
|
+
for (const framework of this.frameworks) {
|
|
454
|
+
out.push(...(await findOrphans(projectRoot, framework, canonical)));
|
|
455
|
+
}
|
|
456
|
+
return out;
|
|
457
|
+
},
|
|
458
|
+
async removeOrphans(projectRoot, framework) {
|
|
459
|
+
const canonical = new Set(await listCanonicalHookInstances(projectRoot));
|
|
460
|
+
return removeOrphanScripts(projectRoot, framework, canonical);
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
//# sourceMappingURL=hookParityRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookParityRule.js","sourceRoot":"","sources":["../../../../src/providers/parity/rules/hookParityRule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillParityRule — parity rule for the Skill functional primitive.
|
|
3
|
+
*
|
|
4
|
+
* Specs:
|
|
5
|
+
* - specs/instar-concepts/skill.md (canonical shape)
|
|
6
|
+
* - specs/frameworks/claude-code/skills.md (Claude rendering contract)
|
|
7
|
+
* - specs/frameworks/codex-cli/skills.md (Codex rendering contract)
|
|
8
|
+
*
|
|
9
|
+
* Reads canonical skills from `.instar/skills/<name>/` and verifies each
|
|
10
|
+
* framework's rendering is in sync. On drift, the sentinel can call
|
|
11
|
+
* remediate() to re-render from canonical.
|
|
12
|
+
*
|
|
13
|
+
* Convergence-round-1 hardening applied:
|
|
14
|
+
* - C1: strict slug grammar enforced at every entry point (path traversal
|
|
15
|
+
* and arbitrary-write are no longer reachable from canonical content).
|
|
16
|
+
* - C2: YAML parsing via js-yaml; fail-loud on parse error rather than
|
|
17
|
+
* silent truncation by regex.
|
|
18
|
+
* - C5: symmetric verify — orphan rendered files surfaced as
|
|
19
|
+
* `orphan-rendering-found`; remediate cleans them.
|
|
20
|
+
* - C7: rendered files carry an `x-instar-stamp` tag recording the
|
|
21
|
+
* canonical body hash that produced them. user-edits to renderings are
|
|
22
|
+
* detected and surfaced as `user-edit-conflict`; auto-remediate
|
|
23
|
+
* refuses to overwrite without explicit force.
|
|
24
|
+
* - C8: description length capped + control chars stripped at parse time
|
|
25
|
+
* to bound prompt-injection surface.
|
|
26
|
+
* - H1: directory name vs frontmatter `name` mismatch surfaced as
|
|
27
|
+
* `name-directory-mismatch`.
|
|
28
|
+
* - H5: canonical-read errors tagged with `framework: 'canonical'` rather
|
|
29
|
+
* than misleadingly attributing to a framework.
|
|
30
|
+
*
|
|
31
|
+
* Deferred to follow-up issues (tracked, not in this PR):
|
|
32
|
+
* - C3: render `allowed-tools` → Claude frontmatter + Codex
|
|
33
|
+
* `dependencies.tools`. Removed from canonical for v0.1 to avoid
|
|
34
|
+
* promise-without-delivery drift; will land with the Tool primitive.
|
|
35
|
+
* - C6: atomic-write tempfile+rename. Single-sentinel-pass + single-
|
|
36
|
+
* machine narrows the race window for v0.1; will add when sentinel
|
|
37
|
+
* ships.
|
|
38
|
+
* - H2/H3: BackupManager defaults + CLAUDE.md template — separate PRs.
|
|
39
|
+
* - H4: git-sync conflict-marker detection — operator-facing; surfaced
|
|
40
|
+
* in this PR as fail-loud `canonical-parse-error`.
|
|
41
|
+
*/
|
|
42
|
+
import type { ParityRule } from '../types.js';
|
|
43
|
+
export declare class CanonicalSkillError extends Error {
|
|
44
|
+
constructor(message: string);
|
|
45
|
+
}
|
|
46
|
+
export declare const skillParityRule: ParityRule;
|
|
47
|
+
//# sourceMappingURL=skillParityRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillParityRule.d.ts","sourceRoot":"","sources":["../../../../src/providers/parity/rules/skillParityRule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAOH,OAAO,KAAK,EACV,UAAU,EAGX,MAAM,aAAa,CAAC;AAiCrB,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAuhBD,eAAO,MAAM,eAAe,EAAE,UA2E7B,CAAC"}
|