@dzhechkov/harness-core 0.3.126 → 0.3.128
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/.dz-manifest.json +74 -50
- package/README.md +3 -1
- package/dist/delivery-check.d.ts +169 -0
- package/dist/delivery-check.d.ts.map +1 -0
- package/dist/delivery-check.js +334 -0
- package/dist/delivery-check.js.map +1 -0
- package/dist/feature-adr-setup.d.ts +17 -1
- package/dist/feature-adr-setup.d.ts.map +1 -1
- package/dist/feature-adr-setup.js +76 -1
- package/dist/feature-adr-setup.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/parity.d.ts +73 -0
- package/dist/parity.d.ts.map +1 -0
- package/dist/parity.js +189 -0
- package/dist/parity.js.map +1 -0
- package/dist/sign.d.ts.map +1 -1
- package/dist/sign.js +15 -7
- package/dist/sign.js.map +1 -1
- package/package.json +3 -3
- package/sbom.json +145 -85
- package/src/delivery-check.ts +452 -0
- package/src/feature-adr-setup.ts +82 -2
- package/src/index.ts +12 -0
- package/src/parity.ts +231 -0
- package/src/sign.ts +16 -7
package/src/parity.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target-parity model (`dz parity`, feature target-parity-matrix, ADR-001).
|
|
3
|
+
*
|
|
4
|
+
* The honest map of "which harness feature works on which target, and HOW". The matrix does NOT
|
|
5
|
+
* exist as a hand-written document anywhere (the sitedoc lesson, b57e686: a hand-maintained
|
|
6
|
+
* duplicate list is a second drift surface) — this declarative model is the ONLY source, and the
|
|
7
|
+
* table is always COMPUTED from it.
|
|
8
|
+
*
|
|
9
|
+
* Honesty contract (FR-6): a capability flag states only what has been VERIFIED, each with its
|
|
10
|
+
* source in a comment. Unknown support is NOT flagged — a feature falsely promised on a target
|
|
11
|
+
* is worse than one conservatively marked absent.
|
|
12
|
+
*
|
|
13
|
+
* Derivation anchor (FR-4): `TARGET_CAPABILITIES` is typed `Record<TargetName, …>`, so ADDING an
|
|
14
|
+
* 11th target to the registry refuses to compile until it is classified here; the model test
|
|
15
|
+
* re-asserts coverage at runtime and validates every capability reference.
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { TargetName } from './targets.js';
|
|
21
|
+
|
|
22
|
+
/** Runtime capabilities a target platform can provide to harness features. */
|
|
23
|
+
export type RuntimeCapability =
|
|
24
|
+
| 'shell' // can run the dz CLI, i.e. a shell WITH Node.js (what `npm i -g` implies on a dev machine)
|
|
25
|
+
| 'skills' // consumes compiled skills (all adapters emit them; agents-md as one merged file)
|
|
26
|
+
| 'hooks' // pre/post tool-call hooks (auto claim-check, auto recall apply-leg)
|
|
27
|
+
| 'mcp' // Model Context Protocol client exists on the platform (servers still need configuring)
|
|
28
|
+
| 'mcp-configured' // our MCP servers (AgentDB / agentic-qe) are wired up out of the box (.mcp.json)
|
|
29
|
+
| 'workflows' // deterministic multi-agent Workflow runtime (ultracode feature-adr, delivery gate)
|
|
30
|
+
| 'statusline'; // live status line (🚦 gates)
|
|
31
|
+
|
|
32
|
+
/** All declared capabilities — the closed vocabulary the model test validates references against. */
|
|
33
|
+
export const RUNTIME_CAPABILITIES: readonly RuntimeCapability[] = [
|
|
34
|
+
'shell',
|
|
35
|
+
'skills',
|
|
36
|
+
'hooks',
|
|
37
|
+
'mcp',
|
|
38
|
+
'mcp-configured',
|
|
39
|
+
'workflows',
|
|
40
|
+
'statusline',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What each target has been VERIFIED to provide (FR-6: source per line; conservative — an
|
|
45
|
+
* unverified capability stays absent until proven, never assumed).
|
|
46
|
+
*/
|
|
47
|
+
export const TARGET_CAPABILITIES: Record<TargetName, readonly RuntimeCapability[]> = {
|
|
48
|
+
// Daily-driven harness: hooks (claim-check PreToolUse, recall UserPromptSubmit), MCP servers,
|
|
49
|
+
// Workflow runtime and the statusline are all exercised in this repo every session.
|
|
50
|
+
'claude-code': ['shell', 'skills', 'hooks', 'mcp', 'mcp-configured', 'workflows', 'statusline'],
|
|
51
|
+
// MCP subsystem probed live: `codex mcp --help` + `codex mcp list` answer (2026-07-19).
|
|
52
|
+
codex: ['shell', 'skills', 'mcp'],
|
|
53
|
+
// Conservative v1: skills emission verified by the adapters; richer runtimes unproven.
|
|
54
|
+
opencode: ['shell', 'skills'],
|
|
55
|
+
hermes: ['shell', 'skills'],
|
|
56
|
+
openclaude: ['shell', 'skills'],
|
|
57
|
+
copilot: ['shell', 'skills'],
|
|
58
|
+
// Lowest common denominator: one merged AGENTS.md — skills arrive as a single managed file.
|
|
59
|
+
'agents-md': ['shell', 'skills'],
|
|
60
|
+
cursor: ['shell', 'skills'],
|
|
61
|
+
gemini: ['shell', 'skills'],
|
|
62
|
+
windsurf: ['shell', 'skills'],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** How a feature manifests on a platform: a concrete FORM with its runtime requirements. */
|
|
66
|
+
export interface FeatureForm {
|
|
67
|
+
/** Human-readable name of the form, shown as the `via` of a parity cell (AM-2). */
|
|
68
|
+
readonly form: string;
|
|
69
|
+
readonly requires: readonly RuntimeCapability[];
|
|
70
|
+
/** `full` = the complete experience; `manual` = works, but the user drives it by hand. */
|
|
71
|
+
readonly level: 'full' | 'manual';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ParityFeature {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly title: string;
|
|
77
|
+
readonly forms: readonly FeatureForm[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The harness feature inventory for the parity map. A feature may carry SEVERAL forms — parity
|
|
82
|
+
* for a target is the BEST form whose requirements the target provides (e.g. claim-check: the
|
|
83
|
+
* hook form is automatic on every Write/Edit; the CLI form works anywhere but must be invoked).
|
|
84
|
+
*/
|
|
85
|
+
export const PARITY_FEATURES: readonly ParityFeature[] = [
|
|
86
|
+
{
|
|
87
|
+
id: 'dz-cli',
|
|
88
|
+
title: 'dz CLI (all commands)',
|
|
89
|
+
forms: [{ form: 'shell command', requires: ['shell'], level: 'full' }],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'skills-packs',
|
|
93
|
+
title: 'Skill packs (compiled per target)',
|
|
94
|
+
forms: [{ form: 'compiled skills via adapter', requires: ['skills'], level: 'full' }],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'feature-adr',
|
|
98
|
+
title: 'feature-adr pipeline',
|
|
99
|
+
forms: [
|
|
100
|
+
{ form: 'ultracode deterministic workflow', requires: ['workflows'], level: 'full' },
|
|
101
|
+
{ form: 'interactive skill (plain /feature-adr)', requires: ['skills'], level: 'manual' },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: 'delivery-gate',
|
|
106
|
+
title: 'Step-10 Delivery Gate',
|
|
107
|
+
forms: [
|
|
108
|
+
{ form: 'workflow delivery block', requires: ['workflows'], level: 'full' },
|
|
109
|
+
// Portable form (portable-gates, run #3): the CLI runs the deterministic parts (artifact probes,
|
|
110
|
+
// hand-off arithmetic, cross-validation bookkeeping) and DISPATCHES the semantic review to the
|
|
111
|
+
// target's own agent runtime — the `dz challenge` cartridge precedent. Requires only `shell`.
|
|
112
|
+
{ form: 'dz delivery-check (CLI 4-plane hand-off protocol)', requires: ['shell'], level: 'manual' },
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'challenge-panel',
|
|
117
|
+
title: 'Adversarial challenge-panel (plan gate)',
|
|
118
|
+
forms: [
|
|
119
|
+
{ form: 'workflow plan gate', requires: ['workflows'], level: 'full' },
|
|
120
|
+
{ form: 'dz challenge (CLI)', requires: ['shell'], level: 'manual' },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'claim-check',
|
|
125
|
+
title: 'Integrity claim-check',
|
|
126
|
+
forms: [
|
|
127
|
+
{ form: 'PreToolUse hook (automatic on Write/Edit)', requires: ['hooks'], level: 'full' },
|
|
128
|
+
{ form: 'dz claim-check (CLI) + publish gate', requires: ['shell'], level: 'manual' },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'learning-collect',
|
|
133
|
+
title: 'Self-learning: collect + rank (dz teach/recall)',
|
|
134
|
+
forms: [{ form: 'dz teach / consolidate / recall', requires: ['shell'], level: 'full' }],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'learning-apply',
|
|
138
|
+
title: 'Self-learning: automatic apply-leg',
|
|
139
|
+
forms: [
|
|
140
|
+
{ form: 'UserPromptSubmit hook (auto recall)', requires: ['hooks'], level: 'full' },
|
|
141
|
+
{ form: 'manual dz recall before a task', requires: ['shell'], level: 'manual' },
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: 'statusline-gates',
|
|
146
|
+
title: 'Live 🚦 gates status line',
|
|
147
|
+
forms: [{ form: 'statusline integration', requires: ['statusline'], level: 'full' }],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'project-guards',
|
|
151
|
+
title: 'Deterministic project guards (setup --guards)',
|
|
152
|
+
forms: [{ form: 'zero-dependency check.mjs (runs anywhere node runs)', requires: ['shell'], level: 'full' }],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'release-signing',
|
|
156
|
+
title: 'Verified release + signing (dz release/sign/sbom)',
|
|
157
|
+
forms: [{ form: 'dz release / sign / sbom / publish', requires: ['shell'], level: 'full' }],
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 'mcp-memory',
|
|
161
|
+
title: 'MCP memory (AgentDB, agentic-qe)',
|
|
162
|
+
forms: [
|
|
163
|
+
{ form: 'preconfigured MCP servers (.mcp.json ships in-repo)', requires: ['mcp-configured'], level: 'full' },
|
|
164
|
+
{ form: 'manual MCP server config (e.g. `codex mcp add`)', requires: ['mcp'], level: 'manual' },
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Short column labels for the grid renderer — kept NEXT TO the model and covered by the same
|
|
171
|
+
* coverage test (a hand map in the CLI would be a second, unchecked target registry).
|
|
172
|
+
*/
|
|
173
|
+
export const TARGET_SHORT_LABELS: Record<TargetName, string> = {
|
|
174
|
+
'claude-code': 'cc',
|
|
175
|
+
codex: 'cdx',
|
|
176
|
+
opencode: 'ocd',
|
|
177
|
+
hermes: 'hrm',
|
|
178
|
+
openclaude: 'ocl',
|
|
179
|
+
copilot: 'cop',
|
|
180
|
+
'agents-md': 'amd',
|
|
181
|
+
cursor: 'cur',
|
|
182
|
+
gemini: 'gem',
|
|
183
|
+
windsurf: 'wsf',
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The quality-GATE class of features — what the scaffolded gates doc lists under "Gates runnable
|
|
188
|
+
* here" (a full parity dump put "Skill packs — full" under a gates heading; delivery finding).
|
|
189
|
+
* Must stay a subset of PARITY_FEATURES ids (pinned by test).
|
|
190
|
+
*/
|
|
191
|
+
export const GATE_FEATURE_IDS: readonly string[] = [
|
|
192
|
+
'feature-adr',
|
|
193
|
+
'delivery-gate',
|
|
194
|
+
'challenge-panel',
|
|
195
|
+
'claim-check',
|
|
196
|
+
'project-guards',
|
|
197
|
+
'release-signing',
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
/** One computed parity cell: the best available form for a feature on a target. */
|
|
201
|
+
export interface ParityCell {
|
|
202
|
+
readonly level: 'full' | 'manual' | 'none';
|
|
203
|
+
/** Which form delivers it (absent only when level is `none`) — AM-2: "partial" must name its path. */
|
|
204
|
+
readonly via?: string | undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Compute the parity cell for one feature on one target (pure; best form wins, `full` first). */
|
|
208
|
+
export function computeParity(feature: ParityFeature, capabilities: readonly RuntimeCapability[]): ParityCell {
|
|
209
|
+
const caps = new Set(capabilities);
|
|
210
|
+
const usable = feature.forms.filter((f) => f.requires.every((r) => caps.has(r)));
|
|
211
|
+
const full = usable.find((f) => f.level === 'full');
|
|
212
|
+
if (full !== undefined) return { level: 'full', via: full.form };
|
|
213
|
+
const manual = usable.find((f) => f.level === 'manual');
|
|
214
|
+
if (manual !== undefined) return { level: 'manual', via: manual.form };
|
|
215
|
+
return { level: 'none' };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface ParityMatrixRow {
|
|
219
|
+
readonly feature: ParityFeature;
|
|
220
|
+
readonly cells: Readonly<Record<TargetName, ParityCell>>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The full computed matrix over every declared feature × every registered target. */
|
|
224
|
+
export function buildParityMatrix(): ParityMatrixRow[] {
|
|
225
|
+
const targets = Object.keys(TARGET_CAPABILITIES) as TargetName[];
|
|
226
|
+
return PARITY_FEATURES.map((feature) => {
|
|
227
|
+
const cells = {} as Record<TargetName, ParityCell>;
|
|
228
|
+
for (const t of targets) cells[t] = computeParity(feature, TARGET_CAPABILITIES[t]);
|
|
229
|
+
return { feature, cells };
|
|
230
|
+
});
|
|
231
|
+
}
|
package/src/sign.ts
CHANGED
|
@@ -113,23 +113,32 @@ export function checkManifestEntries(files: unknown): string | null {
|
|
|
113
113
|
return null;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Directory names that are NOT pack content and are excluded from BOTH walks. node_modules/.git:
|
|
118
|
+
* installed deps / VCS metadata. `.agentic-qe`/`.dz`: LOCAL RUNTIME STATE (learning DBs, RVF
|
|
119
|
+
* stores, witness keys) that background workers create inside pack cwds — gitignored, machine-
|
|
120
|
+
* specific, never shipped. Signing them made 19 packs verify green LOCALLY (files present, hashes
|
|
121
|
+
* match) and TAMPERED in CI (clean checkout lacks the gitignored state) — found live on GH run
|
|
122
|
+
* #103, 2026-07-19. State is not content; the walks must never see it.
|
|
123
|
+
*/
|
|
124
|
+
const EXCLUDED_DIRS = new Set(['node_modules', '.git', '.agentic-qe', '.dz']);
|
|
125
|
+
|
|
116
126
|
/** Every file under `root`, POSIX-relative, excluding the manifest and the SBOM themselves. */
|
|
117
127
|
export function listPackFiles(root: string): string[] {
|
|
118
128
|
const out: string[] = [];
|
|
119
129
|
const walk = (dir: string, rel: string): void => {
|
|
120
130
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
if (e.name === 'node_modules' || e.name === '.git') continue;
|
|
131
|
+
// Excluded dirs are unsigned territory BY DESIGN (see EXCLUDED_DIRS). The SIGN and VERIFY
|
|
132
|
+
// walks MUST share these exclusions: an asymmetry here false-TAMPERs every pnpm workspace
|
|
133
|
+
// pack whose node_modules holds symlinks (found live arming task #36 — 10 of 23 packs).
|
|
134
|
+
if (EXCLUDED_DIRS.has(e.name)) continue;
|
|
126
135
|
if (e.name === MANIFEST_NAME || e.name === SBOM_NAME) continue;
|
|
127
136
|
const abs = join(dir, e.name);
|
|
128
137
|
const r = rel ? rel + '/' + e.name : e.name;
|
|
129
138
|
if (e.isDirectory()) walk(abs, r);
|
|
130
139
|
// NOT else-isFile: a symlink (or other non-file) OUTSIDE the excluded dirs must stay VISIBLE to the
|
|
131
140
|
// verify sweep — it fails as "present but not signed" / "is a symlink" (R3-4: a smuggled symlink is a
|
|
132
|
-
// finding, not something to silently ignore). Only
|
|
141
|
+
// finding, not something to silently ignore). Only EXCLUDED_DIRS are exempt territory.
|
|
133
142
|
else out.push(r);
|
|
134
143
|
}
|
|
135
144
|
};
|
|
@@ -146,7 +155,7 @@ export function listSignablePackFiles(root: string): string[] {
|
|
|
146
155
|
const out: string[] = [];
|
|
147
156
|
const walk = (dir: string, rel: string): void => {
|
|
148
157
|
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
149
|
-
if (
|
|
158
|
+
if (EXCLUDED_DIRS.has(e.name)) continue;
|
|
150
159
|
if (e.name === MANIFEST_NAME || e.name === SBOM_NAME) continue;
|
|
151
160
|
const abs = join(dir, e.name);
|
|
152
161
|
const r = rel ? rel + '/' + e.name : e.name;
|