harness-everything 0.20.0 → 0.20.2

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.
@@ -10,7 +10,7 @@
10
10
  "name": "harness-everything",
11
11
  "source": "./",
12
12
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
13
- "version": "0.20.0",
13
+ "version": "0.20.2",
14
14
  "author": {
15
15
  "name": "Miya Daniel"
16
16
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-everything",
3
3
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
4
- "version": "0.20.0",
4
+ "version": "0.20.2",
5
5
  "author": {
6
6
  "name": "Miya Daniel"
7
7
  },
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.20.2](https://github.com/dyphn1/Harness-everything/compare/v0.20.1...v0.20.2) (2026-09-22)
6
+
7
+ ### Bug Fixes
8
+
9
+ * **distribution:** handle legacy claude flags ([2e09915](https://github.com/dyphn1/Harness-everything/commit/2e09915cff6c7cbf7cd10b08587df18264403a01)), closes [#221](https://github.com/dyphn1/Harness-everything/issues/221)
10
+
11
+ ## [0.20.1](https://github.com/dyphn1/Harness-everything/compare/v0.20.0...v0.20.1) (2026-09-22)
12
+
13
+ ### Bug Fixes
14
+
15
+ * **distribution:** support older claude plugin clis ([e00e665](https://github.com/dyphn1/Harness-everything/commit/e00e665eeebf6d1f6fc0469eed435ec0562bc226)), closes [#221](https://github.com/dyphn1/Harness-everything/issues/221)
16
+
5
17
  ## [0.20.0](https://github.com/dyphn1/Harness-everything/compare/v0.19.1...v0.20.0) (2026-09-21)
6
18
 
7
19
  ### Features
@@ -12,7 +12,7 @@ const {
12
12
 
13
13
  const ROOT = path.resolve(__dirname, '..');
14
14
 
15
- function fakeHost({ claudeInstalled = false, codexInstalled = false, claudeMarketplace = true, codexMarketplace = true, unknownClaudePluginState = false } = {}) {
15
+ function fakeHost({ claudeInstalled = false, codexInstalled = false, claudeMarketplace = true, codexMarketplace = true, unknownClaudePluginState = false, unknownClaudeYesFlag = false, unknownClaudeJsonFlag = false } = {}) {
16
16
  const calls = [];
17
17
  const state = {
18
18
  claudeInstalled,
@@ -44,6 +44,12 @@ function fakeHost({ claudeInstalled = false, codexInstalled = false, claudeMarke
44
44
  if (unknownClaudePluginState) return { status: 1, stdout: '', stderr: 'unsupported list' };
45
45
  return { status: 0, stdout: state.claudeInstalled ? 'harness-everything@harness-everything\n' : '', stderr: '' };
46
46
  }
47
+ if (unknownClaudeYesFlag && joined.includes('--yes')) {
48
+ return { status: 1, stdout: '', stderr: "error: unknown option '--yes'" };
49
+ }
50
+ if (unknownClaudeJsonFlag && joined.includes('--json')) {
51
+ return { status: 1, stdout: '', stderr: "error: unknown option '--json'" };
52
+ }
47
53
  if (joined.startsWith('plugin install') || joined.startsWith('plugin update')) {
48
54
  state.claudeInstalled = true;
49
55
  return { status: 0, stdout: '{}', stderr: '' };
@@ -118,6 +124,28 @@ assert.strictEqual(findPlugin({ plugins: [{ id: 'harness-everything@harness-ever
118
124
  assert.strictEqual(callsFor(fake.calls, 'claude', 'plugin install').length, 0, 'installed Claude plugin must not reinstall');
119
125
  }
120
126
 
127
+ {
128
+ const fake = fakeHost({ claudeInstalled: true, unknownClaudeYesFlag: true });
129
+ const result = runHost('claude', fake);
130
+ const updateCalls = callsFor(fake.calls, 'claude', 'plugin update');
131
+ assert.strictEqual(result.failed, 0, 'unsupported Claude --yes must fall back to a compatible update command');
132
+ assert.strictEqual(result.results[0].action, 'update');
133
+ assert.strictEqual(updateCalls.length, 2, 'unsupported --yes must cause one compatibility retry');
134
+ assert.ok(updateCalls[0].args.includes('--yes'), 'first update attempt should use the current non-interactive flag');
135
+ assert.ok(!updateCalls[1].args.includes('--yes'), 'compatibility retry must omit unsupported --yes');
136
+ }
137
+
138
+ {
139
+ const fake = fakeHost({ claudeInstalled: true, unknownClaudeYesFlag: true, unknownClaudeJsonFlag: true });
140
+ const result = runHost('claude', fake);
141
+ const updateCalls = callsFor(fake.calls, 'claude', 'plugin update');
142
+ assert.strictEqual(result.failed, 0, 'unsupported Claude --yes and --json must fall back to a compatible update command');
143
+ assert.strictEqual(updateCalls.length, 3, 'each unsupported option must cause one compatibility retry');
144
+ assert.ok(updateCalls[0].args.includes('--yes') && updateCalls[0].args.includes('--json'), 'first update attempt should use current flags');
145
+ assert.ok(!updateCalls[1].args.includes('--yes') && updateCalls[1].args.includes('--json'), 'second attempt should omit only unsupported --yes');
146
+ assert.ok(!updateCalls[2].args.includes('--yes') && !updateCalls[2].args.includes('--json'), 'final attempt must omit both unsupported flags');
147
+ }
148
+
121
149
  {
122
150
  const fake = fakeHost({ codexInstalled: false });
123
151
  const result = runHost('codex', fake);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-enforcement",
3
3
  "description": "Repository inventory for the opencode enforcement plugin and its standalone helper",
4
- "version": "0.20.0",
4
+ "version": "0.20.2",
5
5
  "runtime": "index.mjs",
6
6
  "hooks": {
7
7
  "verify": "hooks/verify.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
4
4
  "description": "Harness OS: An Orchestrated Agent Operating System for AI-driven Development",
5
5
  "main": "harness-everything/scripts/bootstrap.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
4
4
  "description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
5
5
  "author": {
6
6
  "name": "Miya Daniel",
@@ -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.20.0",
4
+ "version": "0.20.2",
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",
package/sbom.cdx.json CHANGED
@@ -2,23 +2,23 @@
2
2
  "$schema": "https://cyclonedx.org/schema/bom-1.7.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.7",
5
- "serialNumber": "urn:uuid:4a1f9475-5e4e-546c-884f-2449e48966ef",
5
+ "serialNumber": "urn:uuid:338bfdd5-e2e1-5e75-b6b1-f114ba76e2f5",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-21T15:41:05.053Z",
8
+ "timestamp": "2026-09-22T01:26:05.707Z",
9
9
  "tools": [
10
10
  {
11
11
  "vendor": "Harness Everything",
12
12
  "name": "generate-sbom.js",
13
- "version": "0.20.0"
13
+ "version": "0.20.2"
14
14
  }
15
15
  ],
16
16
  "component": {
17
17
  "type": "application",
18
- "bom-ref": "pkg:npm/harness-everything@0.20.0",
18
+ "bom-ref": "pkg:npm/harness-everything@0.20.2",
19
19
  "name": "harness-everything",
20
- "version": "0.20.0",
21
- "purl": "pkg:npm/harness-everything@0.20.0"
20
+ "version": "0.20.2",
21
+ "purl": "pkg:npm/harness-everything@0.20.2"
22
22
  }
23
23
  },
24
24
  "components": [
@@ -1999,7 +1999,7 @@
1999
1999
  ]
2000
2000
  },
2001
2001
  {
2002
- "ref": "pkg:npm/harness-everything@0.20.0",
2002
+ "ref": "pkg:npm/harness-everything@0.20.2",
2003
2003
  "dependsOn": [
2004
2004
  "pkg:npm/%40commitlint/cli@19.8.1",
2005
2005
  "pkg:npm/%40commitlint/config-conventional@19.8.1",
@@ -162,14 +162,14 @@ function createContext(options = {}) {
162
162
  return context;
163
163
  }
164
164
 
165
- function invoke(context, command, args, { mutate = false, label = command } = {}) {
165
+ function invoke(context, command, args, { mutate = false, label = command, warnOnFailure = true } = {}) {
166
166
  const rendered = commandLine(command, args);
167
167
  if (mutate && context.dryRun) {
168
168
  context.log(`[dry-run] ${rendered}`);
169
169
  return { status: 0, stdout: '', stderr: '', dryRun: true };
170
170
  }
171
171
  const result = context.runner(command, args, { label });
172
- if (!result || result.status !== 0) {
172
+ if (warnOnFailure && (!result || result.status !== 0)) {
173
173
  context.warn(`[failed] ${rendered}\n ${resultError(result)}`);
174
174
  }
175
175
  return result || { status: 1, stdout: '', stderr: 'runner returned no result' };
@@ -179,6 +179,41 @@ function query(context, command, args) {
179
179
  return context.runner(command, args, { query: true }) || { status: 1, stdout: '', stderr: 'runner returned no result' };
180
180
  }
181
181
 
182
+ function hasUnknownOption(result, option) {
183
+ const output = [result && result.stderr, result && result.stdout, result && result.error && result.error.message]
184
+ .map(value => String(value || ''))
185
+ .join('\n');
186
+ return new RegExp(`unknown option\\s+['"]?${escapeRegExp(option)}['"]?`, 'i').test(output);
187
+ }
188
+
189
+ function runClaudePluginMutation(context, action, pluginId) {
190
+ const baseArgs = [
191
+ 'plugin', action, pluginId,
192
+ '--scope', 'user'
193
+ ];
194
+ let args = [...baseArgs, '--yes', '--json'];
195
+ let attempt = 0;
196
+
197
+ while (true) {
198
+ const result = invoke(context, 'claude', args, {
199
+ mutate: true,
200
+ label: attempt === 0 ? `claude plugin ${action}` : `claude plugin ${action} compatibility retry`,
201
+ warnOnFailure: false
202
+ });
203
+ if (result.status === 0) return result;
204
+
205
+ const unsupported = ['--yes', '--json'].find(option => args.includes(option) && hasUnknownOption(result, option));
206
+ if (!unsupported) {
207
+ context.warn(`[failed] ${commandLine('claude', args)}\n ${resultError(result)}`);
208
+ return result;
209
+ }
210
+
211
+ args = args.filter(arg => arg !== unsupported);
212
+ attempt += 1;
213
+ context.warn(`[notice] Claude CLI does not support ${unsupported}; retrying ${action} without that option.`);
214
+ }
215
+ }
216
+
182
217
  function listState(context, { command, jsonArgs, plainArgs, detectJson, detectText }) {
183
218
  const jsonResult = query(context, command, jsonArgs);
184
219
  if (jsonResult.status === 0) {
@@ -314,10 +349,11 @@ function syncClaude(context) {
314
349
  if (!refreshed.ok) return { host: 'claude', status: 'failed', error: refreshed.error };
315
350
 
316
351
  const action = installed.value ? 'update' : 'install';
317
- const result = invoke(context, 'claude', [
318
- 'plugin', action, `${context.plugin}@${context.marketplace}`,
319
- '--scope', 'user', '--yes', '--json'
320
- ], { mutate: true, label: `claude plugin ${action}` });
352
+ const result = runClaudePluginMutation(
353
+ context,
354
+ action,
355
+ `${context.plugin}@${context.marketplace}`
356
+ );
321
357
  if (result.status !== 0) return { host: 'claude', status: 'failed', error: resultError(result) };
322
358
 
323
359
  const verification = verifyPlugin(context, 'Claude', queryClaudePlugin);