claude-dev-env 1.52.1 → 1.54.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.
@@ -0,0 +1,81 @@
1
+ import { test } from 'node:test';
2
+ import { strict as assert } from 'node:assert';
3
+ import { readFileSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { dirname, join } from 'node:path';
6
+
7
+ const workflowDirectory = dirname(fileURLToPath(import.meta.url));
8
+ const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
9
+
10
+ function sourceSliceBetween(startNeedle, endNeedle) {
11
+ const sliceStart = convergeSource.indexOf(startNeedle);
12
+ assert.notEqual(sliceStart, -1, `expected ${startNeedle} to exist`);
13
+ const sliceEnd = convergeSource.indexOf(endNeedle, sliceStart + startNeedle.length);
14
+ assert.notEqual(sliceEnd, -1, `expected ${endNeedle} to exist after ${startNeedle}`);
15
+ return convergeSource.slice(sliceStart, sliceEnd);
16
+ }
17
+
18
+ const productionModule = new Function(
19
+ `${sourceSliceBetween('function normalizeRunInput(', '\nconst runInput =')}\n` +
20
+ 'return { normalizeRunInput, classifyRunInput };',
21
+ )();
22
+
23
+ const { normalizeRunInput, classifyRunInput } = productionModule;
24
+
25
+ const VALID_COORDINATES = { owner: 'jl-cmd', repo: 'claude-code-config', prNumber: 543 };
26
+
27
+ test('an object payload passes through unchanged', () => {
28
+ assert.deepEqual(normalizeRunInput(VALID_COORDINATES), VALID_COORDINATES);
29
+ });
30
+
31
+ test('a JSON-encoded string payload is parsed into coordinates', () => {
32
+ assert.deepEqual(normalizeRunInput(JSON.stringify(VALID_COORDINATES)), VALID_COORDINATES);
33
+ });
34
+
35
+ test('a non-JSON string returns null rather than throwing', () => {
36
+ assert.equal(normalizeRunInput('not json at all'), null);
37
+ });
38
+
39
+ test('an empty string returns null rather than throwing', () => {
40
+ assert.equal(normalizeRunInput(''), null);
41
+ });
42
+
43
+ test('classifyRunInput accepts coordinates carrying owner, repo, and prNumber', () => {
44
+ const classified = classifyRunInput(VALID_COORDINATES);
45
+ assert.deepEqual(classified.input, VALID_COORDINATES);
46
+ assert.equal(classified.blocker, null);
47
+ });
48
+
49
+ test('classifyRunInput blocks a failed parse with a structured blocker and no input', () => {
50
+ const classified = classifyRunInput('not json at all');
51
+ assert.equal(classified.input, null);
52
+ assert.match(classified.blocker, /coordinates/i);
53
+ });
54
+
55
+ test('classifyRunInput blocks a null payload with a structured blocker', () => {
56
+ const classified = classifyRunInput(null);
57
+ assert.equal(classified.input, null);
58
+ assert.match(classified.blocker, /coordinates/i);
59
+ });
60
+
61
+ test('classifyRunInput blocks a payload missing owner', () => {
62
+ const classified = classifyRunInput({ repo: 'claude-code-config', prNumber: 543 });
63
+ assert.equal(classified.input, null);
64
+ assert.match(classified.blocker, /coordinates/i);
65
+ });
66
+
67
+ test('classifyRunInput blocks a payload missing prNumber', () => {
68
+ const classified = classifyRunInput({ owner: 'jl-cmd', repo: 'claude-code-config' });
69
+ assert.equal(classified.input, null);
70
+ assert.match(classified.blocker, /coordinates/i);
71
+ });
72
+
73
+ test('the top-level run guards an unusable input into a structured blocker before reading input.owner', () => {
74
+ const guardBlock = convergeSource.slice(
75
+ convergeSource.indexOf('const runInput = classifyRunInput('),
76
+ convergeSource.indexOf('const prCoordinates ='),
77
+ );
78
+ assert.match(guardBlock, /runInput\.blocker/);
79
+ assert.match(guardBlock, /converged: false/);
80
+ assert.match(guardBlock, /return/);
81
+ });
@@ -2,7 +2,7 @@
2
2
  name: bugteam
3
3
  description: >-
4
4
  Open pull request audit–fix until convergence: CODE_RULES gate, clean-room
5
- audit (`code-quality-agent`, opus) and fix (`clean-coder`, opus), per-loop
5
+ audit (`code-quality-agent`, opus) and fix (`clean-coder`, fable), per-loop
6
6
  GitHub reviews, 20-audit cap; grant then revoke `.claude/**`. Spawns
7
7
  background subagents (`Agent(..., run_in_background=true)`). Triggers: '/bugteam', 'run
8
8
  the bug team', 'auto-fix the PR until clean', 'loop audit and fix'.
@@ -144,7 +144,7 @@ Spawn:
144
144
  Agent(
145
145
  subagent_type="clean-coder",
146
146
  name="bugfix-pr<N>-loop<L>",
147
- model="opus",
147
+ model="fable",
148
148
  mode="bypassPermissions",
149
149
  run_in_background=true,
150
150
  description="Bugfix PR <N> loop <L>",
@@ -110,7 +110,7 @@ truth.
110
110
 
111
111
  - **Subagent roles (spawned per loop, not at invocation start):**
112
112
  - `bugfind` — `code-quality-agent`, model opus (Opus 4.7 at default xhigh effort)
113
- - `bugfix` — `clean-coder`, model opus (Opus 4.7 at default xhigh effort)
113
+ - `bugfix` — `clean-coder`, model fable
114
114
 
115
115
  ### Loop state block
116
116
 
@@ -107,7 +107,7 @@ Then call `Agent` twice in the same message — the primary clean-coder and the
107
107
  ```
108
108
  Agent(
109
109
  subagent_type="clean-coder",
110
- model="opus",
110
+ model="fable",
111
111
  description="qbug primary audit/fix cycle for PR <number>",
112
112
  prompt="<filled cycle XML; see § Subagent cycle prompt>",
113
113
  run_in_background=False
@@ -113,10 +113,10 @@ def test_contract_should_require_files_opened_in_proof_of_absence() -> None:
113
113
  )
114
114
 
115
115
 
116
- def test_step2_spawn_should_include_model_opus_parameter() -> None:
116
+ def test_step2_spawn_should_include_model_fable_parameter() -> None:
117
117
  skill_text = _load_skill_text()
118
- assert 'model="opus"' in skill_text, (
119
- "Step 2 Agent() spawn template must include model=\"opus\" for the primary subagent"
118
+ assert 'model="fable"' in skill_text, (
119
+ "Step 2 Agent() spawn template must include model=\"fable\" for the primary subagent"
120
120
  )
121
121
 
122
122