claude-dev-env 8.49.2 → 8.49.4
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.
|
@@ -27,7 +27,7 @@ export const USAGE_WRAPUP_PLUGIN_SPEC = Object.freeze({
|
|
|
27
27
|
label: 'Usage-wrapup',
|
|
28
28
|
marketplaceRepository: 'jl-cmd/claude-dev-env',
|
|
29
29
|
marketplaceName: 'claude-dev-env',
|
|
30
|
-
marketplaceAddArguments: Object.freeze(['--sparse', '.claude-plugin']),
|
|
30
|
+
marketplaceAddArguments: Object.freeze(['--sparse', '.claude-plugin', 'packages/usage-wrapup']),
|
|
31
31
|
pluginIdentifier: 'usage-wrapup@claude-dev-env',
|
|
32
32
|
hosts: Object.freeze(['claude']),
|
|
33
33
|
optOutFlag: '--no-usage-wrapup',
|
|
@@ -213,14 +213,12 @@ test('a non-zero exit that is not command-not-found still reads as a failure', (
|
|
|
213
213
|
assert.match(outcome.hosts[0].warning, /rejected the catalog/);
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
-
const USAGE_WRAPUP_PINNED_COMMIT = 'd78c314e5787786e866bf5c4967107365854dc78';
|
|
217
|
-
|
|
218
216
|
test('the usage-wrapup plan adds this repository marketplace and installs the plugin on Claude', () => {
|
|
219
217
|
const plan = marketplacePluginPlan(USAGE_WRAPUP_PLUGIN_SPEC, 'claude');
|
|
220
218
|
assert.equal(plan.executable, 'claude');
|
|
221
219
|
assert.equal(plan.homeVariable, 'CLAUDE_CONFIG_DIR');
|
|
222
220
|
assert.deepEqual(plan.commands, [
|
|
223
|
-
['plugin', 'marketplace', 'add', 'jl-cmd/claude-dev-env', '--sparse', '.claude-plugin'],
|
|
221
|
+
['plugin', 'marketplace', 'add', 'jl-cmd/claude-dev-env', '--sparse', '.claude-plugin', 'packages/usage-wrapup'],
|
|
224
222
|
['plugin', 'install', 'usage-wrapup@claude-dev-env'],
|
|
225
223
|
]);
|
|
226
224
|
});
|
|
@@ -238,7 +236,7 @@ test('installing usage-wrapup runs only the Claude commands, inside the managed
|
|
|
238
236
|
assert.deepEqual(runner.calls.map(call => [call.executable, ...call.commandArguments]), [
|
|
239
237
|
['claude', 'plugin', 'uninstall', 'usage-wrapup@claude-dev-env'],
|
|
240
238
|
['claude', 'plugin', 'marketplace', 'remove', 'claude-dev-env'],
|
|
241
|
-
['claude', 'plugin', 'marketplace', 'add', 'jl-cmd/claude-dev-env', '--sparse', '.claude-plugin'],
|
|
239
|
+
['claude', 'plugin', 'marketplace', 'add', 'jl-cmd/claude-dev-env', '--sparse', '.claude-plugin', 'packages/usage-wrapup'],
|
|
242
240
|
['claude', 'plugin', 'install', 'usage-wrapup@claude-dev-env'],
|
|
243
241
|
]);
|
|
244
242
|
for (const call of runner.calls) {
|
|
@@ -270,7 +268,7 @@ test('the usage-wrapup opt-out flag and variable turn off only usage-wrapup', ()
|
|
|
270
268
|
);
|
|
271
269
|
});
|
|
272
270
|
|
|
273
|
-
test('the repository marketplace lists usage-wrapup from
|
|
271
|
+
test('the repository marketplace lists usage-wrapup from its package folder in this repository', () => {
|
|
274
272
|
const marketplace = JSON.parse(readFileSync(
|
|
275
273
|
new URL('../../../.claude-plugin/marketplace.json', import.meta.url),
|
|
276
274
|
'utf8',
|
|
@@ -279,12 +277,7 @@ test('the repository marketplace lists usage-wrapup from the fork, pinned to the
|
|
|
279
277
|
assert.equal(marketplace.name, marketplaceName);
|
|
280
278
|
const entry = marketplace.plugins.find(plugin => plugin.name === pluginName);
|
|
281
279
|
assert.ok(entry, `the marketplace lists ${pluginName}`);
|
|
282
|
-
assert.
|
|
283
|
-
source: 'github',
|
|
284
|
-
repo: 'jl-cmd/usage-wrapup',
|
|
285
|
-
ref: 'main',
|
|
286
|
-
sha: USAGE_WRAPUP_PINNED_COMMIT,
|
|
287
|
-
});
|
|
280
|
+
assert.equal(entry.source, './packages/usage-wrapup');
|
|
288
281
|
});
|
|
289
282
|
|
|
290
283
|
test('a clean install deletes the orphaned pstack versions and keeps the installed one', () => {
|
package/bin/install.test.mjs
CHANGED
|
@@ -3317,7 +3317,7 @@ test('a pstack install after a --no-pstack install seeds the Codex model sheet',
|
|
|
3317
3317
|
const USAGE_WRAPUP_CLAUDE_COMMANDS = Object.freeze([
|
|
3318
3318
|
'claude plugin uninstall usage-wrapup@claude-dev-env',
|
|
3319
3319
|
'claude plugin marketplace remove claude-dev-env',
|
|
3320
|
-
'claude plugin marketplace add jl-cmd/claude-dev-env --sparse .claude-plugin',
|
|
3320
|
+
'claude plugin marketplace add jl-cmd/claude-dev-env --sparse .claude-plugin packages/usage-wrapup',
|
|
3321
3321
|
'claude plugin install usage-wrapup@claude-dev-env',
|
|
3322
3322
|
]);
|
|
3323
3323
|
|
package/package.json
CHANGED
|
@@ -211,6 +211,7 @@ class _RunContext:
|
|
|
211
211
|
all_attempts: list[tuple[str, str]]
|
|
212
212
|
all_spent_accounts: set[Account]
|
|
213
213
|
all_spent_resets: dict[Account, datetime]
|
|
214
|
+
start_failure_text: str = ""
|
|
214
215
|
|
|
215
216
|
|
|
216
217
|
def _prepare_run(
|
|
@@ -234,7 +235,7 @@ def _wait_outcome(context: _RunContext, decision: Decision) -> JobOutcome:
|
|
|
234
235
|
context.report.final_decision = decision
|
|
235
236
|
all_attempt_statuses = {each_status for _, each_status in context.all_attempts}
|
|
236
237
|
if all_attempt_statuses == {"start_failed"}:
|
|
237
|
-
return JobOutcome(COMMAND_MISSING_EXIT_CODE, "",
|
|
238
|
+
return JobOutcome(COMMAND_MISSING_EXIT_CODE, "", context.start_failure_text, None, tuple(context.all_attempts), "start_failed", None, None)
|
|
238
239
|
status = "exhausted" if context.all_attempts else "wait"
|
|
239
240
|
return JobOutcome(WAIT_EXIT_CODE, "", "", None, tuple(context.all_attempts), status, None, decision.resets_at, decision.reason)
|
|
240
241
|
|
|
@@ -287,6 +288,7 @@ def _attempt_once(context: _RunContext, decision: Decision) -> JobOutcome | None
|
|
|
287
288
|
except (OSError, subprocess.TimeoutExpired) as error:
|
|
288
289
|
status = "timeout" if isinstance(error, subprocess.TimeoutExpired) else "start_failed"
|
|
289
290
|
_record_spent_attempt(context, account, status, COMMAND_MISSING_EXIT_CODE)
|
|
291
|
+
context.start_failure_text = str(error)
|
|
290
292
|
if isinstance(error, subprocess.TimeoutExpired) or not context.all_readings:
|
|
291
293
|
context.report.final_decision = decision
|
|
292
294
|
final_status = "advisor_blocked" if context.product is Product.CLAUDE else status
|
|
@@ -908,6 +908,20 @@ def test_should_record_start_failure_without_launching_a_command_missing_from_pa
|
|
|
908
908
|
assert outcome.returncode == 127
|
|
909
909
|
|
|
910
910
|
|
|
911
|
+
def test_should_keep_the_start_failure_text_when_no_account_can_start(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
912
|
+
monkeypatch.setitem(account_broker.all_product_adapters, Product.CLAUDE, _adapter(
|
|
913
|
+
(_account("first", Product.CLAUDE), _account("second", Product.CLAUDE)),
|
|
914
|
+
{"first": _meters(80, 80), "second": _meters(70, 70)},
|
|
915
|
+
))
|
|
916
|
+
monkeypatch.setattr(shutil, "which", lambda name: None)
|
|
917
|
+
monkeypatch.setattr(account_broker.support.subprocess, "run", lambda *arguments, **options: pytest.fail("a missing command ran"))
|
|
918
|
+
|
|
919
|
+
outcome, _ = account_broker._execute(Product.CLAUDE, ("claude", "-p"), now=NOW)
|
|
920
|
+
|
|
921
|
+
assert outcome.status == "start_failed"
|
|
922
|
+
assert "claude" in outcome.stderr
|
|
923
|
+
|
|
924
|
+
|
|
911
925
|
@pytest.mark.parametrize("marked_name", ["retired", "first"])
|
|
912
926
|
def test_should_run_past_a_stored_spent_mark_beyond_the_platform_range(
|
|
913
927
|
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], marked_name: str
|