harness-everything 0.25.0 ā 0.26.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +36 -0
- package/ci/mechanism-35-verification-contract.test.js +416 -0
- package/ci/mutation-check.js +2 -0
- package/ci/mutation-loader.js +4 -0
- package/docs/audit.md +2 -0
- package/harness-everything/SKILL.md +2 -2
- package/harness-everything/scripts/verify-gate.js +223 -75
- package/hooks/scripts/lib/workflow-isolation.js +3 -4
- package/hooks/scripts/state-persist.js +1 -1
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/hooks/scripts/lib/workflow-isolation.js +3 -4
- package/plugins/harness-everything/hooks/scripts/state-persist.js +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/scripts/lib/verification-contract.js +357 -0
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +2 -2
- package/plugins/harness-everything/skills/harness-everything/scripts/verify-gate.js +223 -75
- package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +14 -13
- package/plugins/harness-everything/skills/using-git-worktrees/references/submodules-in-worktrees.md +135 -0
- package/plugins/harness-everything/skills/verification-loop/SKILL.md +15 -23
- package/plugins/harness-everything/skills/verification-loop/references/project-verification-contract.md +112 -0
- package/plugins/harness-everything/skills/verification-loop/references/verification-phases.md +4 -3
- package/plugins/harness-everything/skills/verification-loop/references/verify-contract.schema.json +32 -0
- package/plugins/harness-everything/skills/verification-loop/references/verify-result.schema.json +65 -0
- package/sbom.cdx.json +7 -7
- package/scripts/lib/verification-contract.js +357 -0
- package/using-git-worktrees/SKILL.md +14 -13
- package/using-git-worktrees/references/submodules-in-worktrees.md +135 -0
- package/verification-loop/SKILL.md +15 -23
- package/verification-loop/references/project-verification-contract.md +112 -0
- package/verification-loop/references/verification-phases.md +4 -3
- package/verification-loop/references/verify-contract.schema.json +32 -0
- package/verification-loop/references/verify-result.schema.json +65 -0
|
@@ -1,100 +1,248 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Runs the target project's own mechanical checks (lint/test scripts from the
|
|
5
|
-
* nearest package.json) and refuses completion (Exit 1) when any of them fail.
|
|
5
|
+
* Harness project verification gate.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* broken project.
|
|
11
|
-
* - HARNESS_SKIP_PROJECT_CHECKS=1 skips the project-script phase (the tmp-file
|
|
12
|
-
* check above still applies). The gate sets it for its own children so a
|
|
13
|
-
* project whose test suite itself drives the Harness runtime (like this repo) cannot
|
|
14
|
-
* recurse back into the gate.
|
|
7
|
+
* Contract: .harness/verify.json
|
|
8
|
+
* Discovery: read-only candidates; legacy package lint/test remains auto-run.
|
|
9
|
+
* UNCHECKED_* is non-blocking control flow and is never passing-test evidence.
|
|
15
10
|
*/
|
|
16
|
-
const { execSync } = require('child_process');
|
|
17
11
|
const fs = require('fs');
|
|
18
12
|
const path = require('path');
|
|
13
|
+
const { spawnSync } = require('child_process');
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
function loadVerificationModel() {
|
|
16
|
+
for (const candidate of [
|
|
17
|
+
path.resolve(__dirname, '../../scripts/lib/verification-contract.js'),
|
|
18
|
+
path.resolve(__dirname, '../../../scripts/lib/verification-contract.js'),
|
|
19
|
+
]) {
|
|
20
|
+
if (fs.existsSync(candidate)) return require(candidate);
|
|
21
|
+
}
|
|
22
|
+
throw new Error('verification-contract runtime is missing from this Harness distribution');
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
const {
|
|
26
|
+
detectRoot,
|
|
27
|
+
enumerateSubmoduleRoots,
|
|
28
|
+
findGitRoot,
|
|
29
|
+
readContract,
|
|
30
|
+
} = loadVerificationModel();
|
|
31
|
+
|
|
32
|
+
const jsonMode = process.argv.includes('--json');
|
|
33
|
+
const cwd = path.resolve(process.cwd());
|
|
34
|
+
const repoRoot = findGitRoot(cwd);
|
|
35
|
+
|
|
36
|
+
function emptyReport(status, reason) {
|
|
37
|
+
return {
|
|
38
|
+
status,
|
|
39
|
+
reason,
|
|
40
|
+
repoRoot,
|
|
41
|
+
roots: [],
|
|
42
|
+
checks: [],
|
|
43
|
+
candidates: [],
|
|
44
|
+
};
|
|
33
45
|
}
|
|
34
46
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
function emit(report) {
|
|
48
|
+
if (jsonMode) {
|
|
49
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('=== š”ļø Harness Verification Gate ===');
|
|
54
|
+
console.log(`Status: ${report.status}`);
|
|
55
|
+
console.log(`Repository: ${report.repoRoot}`);
|
|
56
|
+
if (report.reason) console.log(`Reason: ${report.reason}`);
|
|
57
|
+
|
|
58
|
+
for (const root of report.roots || []) {
|
|
59
|
+
console.log(`\n[${root.status}] ${root.path}`);
|
|
60
|
+
if (root.reason) console.log(` ${root.reason}`);
|
|
61
|
+
for (const check of root.checks || []) {
|
|
62
|
+
const exit = check.exitCode === null ? 'timeout/error' : check.exitCode;
|
|
63
|
+
console.log(` check ${check.id}: ${check.run} (exit ${exit}, ${check.durationMs}ms)`);
|
|
64
|
+
if (check.stdout) process.stdout.write(check.stdout.endsWith('\n') ? check.stdout : check.stdout + '\n');
|
|
65
|
+
if (check.stderr) process.stderr.write(check.stderr.endsWith('\n') ? check.stderr : check.stderr + '\n');
|
|
66
|
+
}
|
|
67
|
+
for (const candidate of root.candidates || []) {
|
|
68
|
+
console.log(` candidate [${candidate.source}]: ${candidate.run}`);
|
|
69
|
+
}
|
|
45
70
|
}
|
|
71
|
+
|
|
72
|
+
if (report.status === 'UNCHECKED_NO_CHECKS' || report.status === 'UNCHECKED_DISCOVERED') {
|
|
73
|
+
console.log('\nExit code is 0 (non-blocking), but NO COMPLETE AUTOMATED EVIDENCE was produced.');
|
|
74
|
+
console.log('PROHIBITED: Do NOT cite this run as proof that tests pass. Perform the listed or project-declared verification first.');
|
|
75
|
+
} else if (report.status === 'PASSED') {
|
|
76
|
+
console.log('\nā
Verification PASSED. Objective project checks completed successfully.');
|
|
77
|
+
} else if (report.status === 'FAILED') {
|
|
78
|
+
console.error('\nā Verification FAILED. Fix the reported check/contract error and run this gate again.');
|
|
79
|
+
} else if (report.status === 'SKIPPED') {
|
|
80
|
+
console.log('ā¹ļø Project checks skipped by HARNESS_SKIP_PROJECT_CHECKS=1.');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function finish(report) {
|
|
85
|
+
emit(report);
|
|
86
|
+
process.exit(report.status === 'FAILED' ? 1 : 0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function statusRank(status) {
|
|
90
|
+
return {
|
|
91
|
+
PASSED: 0,
|
|
92
|
+
UNCHECKED_NO_CHECKS: 1,
|
|
93
|
+
UNCHECKED_DISCOVERED: 2,
|
|
94
|
+
FAILED: 3,
|
|
95
|
+
}[status] ?? 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function aggregateStatus(roots) {
|
|
99
|
+
if (!roots.length) return 'UNCHECKED_NO_CHECKS';
|
|
100
|
+
return roots.reduce((worst, root) => statusRank(root.status) > statusRank(worst) ? root.status : worst, 'PASSED');
|
|
46
101
|
}
|
|
47
102
|
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
103
|
+
function executeCheck(check) {
|
|
104
|
+
const started = Date.now();
|
|
105
|
+
const result = spawnSync(check.run, {
|
|
106
|
+
cwd: check.cwd,
|
|
107
|
+
shell: true,
|
|
108
|
+
encoding: 'utf8',
|
|
109
|
+
windowsHide: true,
|
|
110
|
+
timeout: check.timeoutSec * 1000,
|
|
111
|
+
env: { ...process.env, HARNESS_SKIP_PROJECT_CHECKS: '1' },
|
|
112
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
113
|
+
});
|
|
114
|
+
const durationMs = Date.now() - started;
|
|
115
|
+
const timedOut = !!(result.error && result.error.code === 'ETIMEDOUT');
|
|
116
|
+
const exitCode = typeof result.status === 'number' ? result.status : null;
|
|
117
|
+
return {
|
|
118
|
+
id: check.id,
|
|
119
|
+
run: check.run,
|
|
120
|
+
cwd: check.cwd,
|
|
121
|
+
source: check.source,
|
|
122
|
+
exitCode,
|
|
123
|
+
durationMs,
|
|
124
|
+
timedOut,
|
|
125
|
+
signal: result.signal || null,
|
|
126
|
+
stdout: result.stdout || '',
|
|
127
|
+
stderr: result.stderr || '',
|
|
128
|
+
passed: !timedOut && exitCode === 0,
|
|
129
|
+
};
|
|
53
130
|
}
|
|
54
131
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
132
|
+
function publicCheck(check) {
|
|
133
|
+
return {
|
|
134
|
+
id: check.id,
|
|
135
|
+
run: check.run,
|
|
136
|
+
cwd: check.cwd,
|
|
137
|
+
source: check.source,
|
|
138
|
+
exitCode: check.exitCode,
|
|
139
|
+
durationMs: check.durationMs,
|
|
140
|
+
...(check.timedOut ? { timedOut: true } : {}),
|
|
141
|
+
...(check.signal ? { signal: check.signal } : {}),
|
|
142
|
+
...(!jsonMode && check.stdout ? { stdout: check.stdout } : {}),
|
|
143
|
+
...(!jsonMode && check.stderr ? { stderr: check.stderr } : {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function candidateView(candidate) {
|
|
148
|
+
return {
|
|
149
|
+
source: candidate.source,
|
|
150
|
+
run: candidate.run,
|
|
151
|
+
cwd: candidate.cwd,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function rootReason(status, checks, candidates) {
|
|
156
|
+
if (status === 'FAILED') {
|
|
157
|
+
const failed = checks.find(check => !check.passed);
|
|
158
|
+
if (!failed) return 'verification failed';
|
|
159
|
+
return failed.timedOut
|
|
160
|
+
? `check ${failed.id} timed out after ${failed.durationMs}ms`
|
|
161
|
+
: `check ${failed.id} exited ${failed.exitCode}`;
|
|
63
162
|
}
|
|
163
|
+
if (status === 'UNCHECKED_DISCOVERED') return `${candidates.length} verification candidate(s) detected but not executed`;
|
|
164
|
+
if (status === 'UNCHECKED_NO_CHECKS') return 'no project verification checks were declared or detected';
|
|
165
|
+
return `${checks.length} check(s) passed`;
|
|
64
166
|
}
|
|
65
167
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
168
|
+
function contractPlan(contract) {
|
|
169
|
+
const rootResults = contract.roots.map(root => ({
|
|
170
|
+
path: root.path,
|
|
171
|
+
status: 'UNCHECKED_NO_CHECKS',
|
|
172
|
+
reason: '',
|
|
173
|
+
checks: [],
|
|
174
|
+
candidates: [],
|
|
175
|
+
}));
|
|
176
|
+
const byPath = new Map(rootResults.map(root => [path.resolve(root.path), root]));
|
|
177
|
+
|
|
178
|
+
for (const check of contract.checks) {
|
|
179
|
+
const executed = executeCheck(check);
|
|
180
|
+
const root = byPath.get(path.resolve(check.root));
|
|
181
|
+
root.checks.push(executed);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for (const root of rootResults) {
|
|
185
|
+
root.status = root.checks.length === 0
|
|
186
|
+
? 'UNCHECKED_NO_CHECKS'
|
|
187
|
+
: root.checks.some(check => !check.passed) ? 'FAILED' : 'PASSED';
|
|
188
|
+
root.reason = rootReason(root.status, root.checks, root.candidates);
|
|
189
|
+
}
|
|
190
|
+
return rootResults;
|
|
79
191
|
}
|
|
80
192
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
193
|
+
function discoveredPlan() {
|
|
194
|
+
const roots = [];
|
|
195
|
+
for (const rootPath of enumerateSubmoduleRoots(repoRoot)) {
|
|
196
|
+
const detected = detectRoot(rootPath);
|
|
197
|
+
const executed = detected.checks.map(executeCheck);
|
|
198
|
+
const candidates = detected.candidates;
|
|
199
|
+
const status = executed.some(check => !check.passed)
|
|
200
|
+
? 'FAILED'
|
|
201
|
+
: candidates.length > 0 ? 'UNCHECKED_DISCOVERED'
|
|
202
|
+
: executed.length > 0 ? 'PASSED' : 'UNCHECKED_NO_CHECKS';
|
|
203
|
+
roots.push({
|
|
204
|
+
path: rootPath,
|
|
205
|
+
status,
|
|
206
|
+
reason: rootReason(status, executed, candidates),
|
|
207
|
+
checks: executed,
|
|
208
|
+
candidates,
|
|
90
209
|
});
|
|
91
|
-
console.log(`ā
${name} passed.`);
|
|
92
|
-
} catch (err) {
|
|
93
|
-
console.error(`\nā Verification FAILED: "${runner} run ${name}" exited non-zero${err.signal ? ` (signal ${err.signal})` : ''}.`);
|
|
94
|
-
console.error("Fix the failures above and run this gate again.");
|
|
95
|
-
process.exit(1);
|
|
96
210
|
}
|
|
211
|
+
return roots;
|
|
97
212
|
}
|
|
98
213
|
|
|
99
|
-
|
|
100
|
-
|
|
214
|
+
function finalize(roots) {
|
|
215
|
+
const status = aggregateStatus(roots);
|
|
216
|
+
const failingRoot = roots.find(root => root.status === status);
|
|
217
|
+
const report = {
|
|
218
|
+
status,
|
|
219
|
+
reason: failingRoot ? failingRoot.reason : '',
|
|
220
|
+
repoRoot,
|
|
221
|
+
roots: roots.map(root => ({
|
|
222
|
+
path: root.path,
|
|
223
|
+
status: root.status,
|
|
224
|
+
reason: root.reason,
|
|
225
|
+
checks: root.checks.map(publicCheck),
|
|
226
|
+
candidates: root.candidates.map(candidateView),
|
|
227
|
+
})),
|
|
228
|
+
checks: roots.flatMap(root => root.checks.map(publicCheck)),
|
|
229
|
+
candidates: roots.flatMap(root => root.candidates.map(candidateView)),
|
|
230
|
+
};
|
|
231
|
+
finish(report);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Injection remains first and cannot be bypassed by the recursion guard.
|
|
236
|
+
if (fs.existsSync(path.join(cwd, '.verify-fail.tmp'))) {
|
|
237
|
+
finish(emptyReport('FAILED', '.verify-fail.tmp present (injected failure)'));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (process.env.HARNESS_SKIP_PROJECT_CHECKS === '1') {
|
|
241
|
+
finish(emptyReport('SKIPPED', 'HARNESS_SKIP_PROJECT_CHECKS=1 recursion guard'));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const contract = readContract(repoRoot);
|
|
245
|
+
finalize(contract ? contractPlan(contract) : discoveredPlan());
|
|
246
|
+
} catch (error) {
|
|
247
|
+
finish(emptyReport('FAILED', error && error.message ? error.message : String(error)));
|
|
248
|
+
}
|
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const crypto = require('crypto');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
|
+
const { isVerificationCommand } = require('../../../scripts/lib/verification-contract');
|
|
7
8
|
|
|
8
9
|
function gitRaw(cwd, args, options = {}) {
|
|
9
10
|
const result = spawnSync('git', args, {
|
|
@@ -192,10 +193,8 @@ function linkedWorktree(cwd, boundRoot) {
|
|
|
192
193
|
// Unsupported shell syntax still fails closed.
|
|
193
194
|
const DANGEROUS_FLAG_RE = /\s(?:--(?:output|ext-diff|textconv|exec|pre|pre-glob|pager|open|batch|filters)|-[xoO])(?:\b|=)|\s-(?:exec|execdir|delete|fprint|fprintf)\b/i;
|
|
194
195
|
const READ_ONLY_PREFIX_RE = /^(?:git\s+(?:status|rev-parse|diff|log|show|ls-files|check-ignore)(?:\s|$)|git\s+branch\s+--show-current$|git\s+worktree\s+list(?:\s|$)|gh\s+(?:issue|pr)\s+(?:view|list)(?:\s|$)|gh\s+repo\s+view(?:\s|$)|gh\s+auth\s+status(?:\s|$)|(?:pwd|ls|dir|cat|type|head|tail|wc|stat|rg|grep|echo|Get-Location|Get-ChildItem|Get-Content|Select-String|Test-Path)(?:\s|$))/i;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
function isVerificationShell(command) {
|
|
198
|
-
return VERIFY_COMMAND_RE.test(String(command || ''));
|
|
196
|
+
function isVerificationShell(command, options = {}) {
|
|
197
|
+
return isVerificationCommand(command, options);
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
function isReadOnlySegment(segment) {
|
|
@@ -43,7 +43,7 @@ function processState(payload) {
|
|
|
43
43
|
if (isShell) {
|
|
44
44
|
const commandClass = classifyShell(command);
|
|
45
45
|
if (commandClass !== 'read-only' && commandClass !== 'worktree-setup') state.lastEditAt = Date.now();
|
|
46
|
-
if (!isFailed && isVerificationShell(command)) { state.lastVerifyAt = Date.now(); state.lastVerifyExitCode = exitCode ?? null; }
|
|
46
|
+
if (!isFailed && isVerificationShell(command, { cwd: cwdOf(payload, root), root })) { state.lastVerifyAt = Date.now(); state.lastVerifyExitCode = exitCode ?? null; }
|
|
47
47
|
}
|
|
48
48
|
fs.writeFileSync(stateFile, JSON.stringify(state, null, 2), 'utf8');
|
|
49
49
|
observeTool(payload);
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const crypto = require('crypto');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { spawnSync } = require('child_process');
|
|
7
|
+
const { isVerificationCommand } = require('../../../scripts/lib/verification-contract');
|
|
7
8
|
|
|
8
9
|
function gitRaw(cwd, args, options = {}) {
|
|
9
10
|
const result = spawnSync('git', args, {
|
|
@@ -192,10 +193,8 @@ function linkedWorktree(cwd, boundRoot) {
|
|
|
192
193
|
// Unsupported shell syntax still fails closed.
|
|
193
194
|
const DANGEROUS_FLAG_RE = /\s(?:--(?:output|ext-diff|textconv|exec|pre|pre-glob|pager|open|batch|filters)|-[xoO])(?:\b|=)|\s-(?:exec|execdir|delete|fprint|fprintf)\b/i;
|
|
194
195
|
const READ_ONLY_PREFIX_RE = /^(?:git\s+(?:status|rev-parse|diff|log|show|ls-files|check-ignore)(?:\s|$)|git\s+branch\s+--show-current$|git\s+worktree\s+list(?:\s|$)|gh\s+(?:issue|pr)\s+(?:view|list)(?:\s|$)|gh\s+repo\s+view(?:\s|$)|gh\s+auth\s+status(?:\s|$)|(?:pwd|ls|dir|cat|type|head|tail|wc|stat|rg|grep|echo|Get-Location|Get-ChildItem|Get-Content|Select-String|Test-Path)(?:\s|$))/i;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
function isVerificationShell(command) {
|
|
198
|
-
return VERIFY_COMMAND_RE.test(String(command || ''));
|
|
196
|
+
function isVerificationShell(command, options = {}) {
|
|
197
|
+
return isVerificationCommand(command, options);
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
function isReadOnlySegment(segment) {
|
|
@@ -43,7 +43,7 @@ function processState(payload) {
|
|
|
43
43
|
if (isShell) {
|
|
44
44
|
const commandClass = classifyShell(command);
|
|
45
45
|
if (commandClass !== 'read-only' && commandClass !== 'worktree-setup') state.lastEditAt = Date.now();
|
|
46
|
-
if (!isFailed && isVerificationShell(command)) { state.lastVerifyAt = Date.now(); state.lastVerifyExitCode = exitCode ?? null; }
|
|
46
|
+
if (!isFailed && isVerificationShell(command, { cwd: cwdOf(payload, root), root })) { state.lastVerifyAt = Date.now(); state.lastVerifyExitCode = exitCode ?? null; }
|
|
47
47
|
}
|
|
48
48
|
fs.writeFileSync(stateFile, JSON.stringify(state, null, 2), 'utf8');
|
|
49
49
|
observeTool(payload);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "harness-everything",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.26.0",
|
|
5
5
|
"description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Miya Daniel",
|