@cleocode/adapters 2026.9.8 → 2026.9.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/adapters",
3
- "version": "2026.9.8",
3
+ "version": "2026.9.9",
4
4
  "description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,9 +15,9 @@
15
15
  "@ai-sdk/anthropic": "^3.0.69",
16
16
  "@ai-sdk/openai": "^2.0.53",
17
17
  "ai": "^6.0.168",
18
- "@cleocode/contracts": "2026.9.8",
19
- "@cleocode/caamp": "2026.9.8",
20
- "@cleocode/paths": "2026.9.8"
18
+ "@cleocode/paths": "2026.9.9",
19
+ "@cleocode/caamp": "2026.9.9",
20
+ "@cleocode/contracts": "2026.9.9"
21
21
  },
22
22
  "license": "MIT",
23
23
  "engines": {
@@ -30,7 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@types/node": "^24.3.0",
32
32
  "vitest": "^4.1.4",
33
- "@cleocode/playbooks": "2026.9.8"
33
+ "@cleocode/playbooks": "2026.9.9"
34
34
  },
35
35
  "repository": {
36
36
  "type": "git",
@@ -17,7 +17,7 @@ import {
17
17
  ClaudeCodeSpawnProvider,
18
18
  createClaudeCodeAdapter as createAdapter,
19
19
  } from '@cleocode/adapters';
20
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
20
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
21
21
 
22
22
  describe('ClaudeCodeAdapter — integration', () => {
23
23
  let adapter: ClaudeCodeAdapter;
@@ -155,9 +155,19 @@ describe('ClaudeCodeInstallProvider — integration', () => {
155
155
  install = new ClaudeCodeInstallProvider();
156
156
  testDir = join(tmpdir(), `cleo-adapter-test-${Date.now()}`);
157
157
  mkdirSync(testDir, { recursive: true });
158
+ const fixtureHome = join(testDir, 'fixture-home');
159
+ vi.stubEnv('HOME', fixtureHome);
160
+ vi.stubEnv('USERPROFILE', fixtureHome);
161
+ vi.stubEnv('CLEO_HOME', join(fixtureHome, '.cleo'));
162
+ mkdirSync(join(fixtureHome, '.cleo', 'templates'), { recursive: true });
163
+ writeFileSync(
164
+ join(fixtureHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
165
+ 'Fixture protocol: inspect authority and coverage.',
166
+ );
158
167
  });
159
168
 
160
169
  afterEach(() => {
170
+ vi.unstubAllEnvs();
161
171
  try {
162
172
  rmSync(testDir, { recursive: true, force: true });
163
173
  } catch {
@@ -165,15 +175,15 @@ describe('ClaudeCodeInstallProvider — integration', () => {
165
175
  }
166
176
  });
167
177
 
168
- it('creates CLAUDE.md with @-references', async () => {
178
+ it('creates CLAUDE.md with embedded protocol', async () => {
169
179
  await install.ensureInstructionReferences(testDir);
170
180
  const content = readFileSync(join(testDir, 'CLAUDE.md'), 'utf-8');
171
- // Structure check: must be a non-empty @~/... path pointing to CLEO-INJECTION.md (OS-agnostic)
172
- expect(content).toMatch(/@~\/.+\/CLEO-INJECTION\.md/);
173
- expect(content).toContain('@.cleo/memory-bridge.md');
181
+ expect(content).toContain('Fixture protocol: inspect authority and coverage.');
182
+ expect(content).toContain('Project memory bridge unavailable.');
183
+ expect(content).not.toContain('@.cleo/memory-bridge.md');
174
184
  });
175
185
 
176
- it('appends missing references to existing CLAUDE.md', async () => {
186
+ it('embeds protocol while preserving existing CLAUDE.md', async () => {
177
187
  const existing = '# Project\n@AGENTS.md\n';
178
188
  writeFileSync(join(testDir, 'CLAUDE.md'), existing, 'utf-8');
179
189
 
@@ -181,23 +191,24 @@ describe('ClaudeCodeInstallProvider — integration', () => {
181
191
  const content = readFileSync(join(testDir, 'CLAUDE.md'), 'utf-8');
182
192
  expect(content).toContain('# Project');
183
193
  expect(content).toContain('@AGENTS.md');
184
- // Structure check: must be a non-empty @~/... path pointing to CLEO-INJECTION.md (OS-agnostic)
185
- expect(content).toMatch(/@~\/.+\/CLEO-INJECTION\.md/);
186
- expect(content).toContain('@.cleo/memory-bridge.md');
194
+ expect(content).toContain('Fixture protocol: inspect authority and coverage.');
195
+ expect(content).toContain('Project memory bridge unavailable.');
196
+ expect(content).not.toContain('@.cleo/memory-bridge.md');
187
197
  });
188
198
 
189
199
  it('is idempotent — calling twice does not duplicate the CAAMP block', async () => {
190
200
  // First call creates the CAAMP-managed block
191
201
  await install.ensureInstructionReferences(testDir);
192
202
  const firstContent = readFileSync(join(testDir, 'CLAUDE.md'), 'utf-8');
193
- const firstCount = (firstContent.match(/@~\/.+\/CLEO-INJECTION\.md/g) ?? []).length;
203
+ const firstCount = (firstContent.match(/<!-- CAAMP:START -->/g) ?? []).length;
194
204
  expect(firstCount).toBe(1);
195
205
 
196
206
  // Second call must be idempotent — CAAMP detects existing block and returns 'intact'
197
207
  await install.ensureInstructionReferences(testDir);
198
208
  const secondContent = readFileSync(join(testDir, 'CLAUDE.md'), 'utf-8');
199
- const secondCount = (secondContent.match(/@~\/.+\/CLEO-INJECTION\.md/g) ?? []).length;
209
+ const secondCount = (secondContent.match(/<!-- CAAMP:START -->/g) ?? []).length;
200
210
  expect(secondCount).toBe(1);
211
+ expect(secondContent).toBe(firstContent);
201
212
  });
202
213
 
203
214
  it('install returns expected shape', async () => {
@@ -16,7 +16,7 @@ import {
16
16
  CursorInstallProvider,
17
17
  createCursorAdapter as createAdapter,
18
18
  } from '@cleocode/adapters';
19
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
19
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
20
20
 
21
21
  describe('CursorAdapter — integration', () => {
22
22
  let adapter: CursorAdapter;
@@ -138,9 +138,19 @@ describe('CursorInstallProvider — integration', () => {
138
138
  install = new CursorInstallProvider();
139
139
  testDir = join(tmpdir(), `cleo-cursor-test-${Date.now()}`);
140
140
  mkdirSync(testDir, { recursive: true });
141
+ const fixtureHome = join(testDir, 'fixture-home');
142
+ vi.stubEnv('HOME', fixtureHome);
143
+ vi.stubEnv('USERPROFILE', fixtureHome);
144
+ vi.stubEnv('CLEO_HOME', join(fixtureHome, '.cleo'));
145
+ mkdirSync(join(fixtureHome, '.cleo', 'templates'), { recursive: true });
146
+ writeFileSync(
147
+ join(fixtureHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
148
+ 'Fixture protocol: inspect authority and coverage.',
149
+ );
141
150
  });
142
151
 
143
152
  afterEach(() => {
153
+ vi.unstubAllEnvs();
144
154
  try {
145
155
  rmSync(testDir, { recursive: true, force: true });
146
156
  } catch {
@@ -17,7 +17,7 @@ import {
17
17
  OpenCodeInstallProvider,
18
18
  OpenCodeSpawnProvider,
19
19
  } from '@cleocode/adapters';
20
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
20
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
21
21
 
22
22
  describe('OpenCodeAdapter — integration', () => {
23
23
  let adapter: OpenCodeAdapter;
@@ -189,9 +189,19 @@ describe('OpenCodeInstallProvider — integration', () => {
189
189
  install = new OpenCodeInstallProvider();
190
190
  testDir = join(tmpdir(), `cleo-opencode-test-${Date.now()}`);
191
191
  mkdirSync(testDir, { recursive: true });
192
+ const fixtureHome = join(testDir, 'fixture-home');
193
+ vi.stubEnv('HOME', fixtureHome);
194
+ vi.stubEnv('USERPROFILE', fixtureHome);
195
+ vi.stubEnv('CLEO_HOME', join(fixtureHome, '.cleo'));
196
+ mkdirSync(join(fixtureHome, '.cleo', 'templates'), { recursive: true });
197
+ writeFileSync(
198
+ join(fixtureHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
199
+ 'Fixture protocol: inspect authority and coverage.',
200
+ );
192
201
  });
193
202
 
194
203
  afterEach(() => {
204
+ vi.unstubAllEnvs();
195
205
  try {
196
206
  rmSync(testDir, { recursive: true, force: true });
197
207
  } catch {
@@ -199,24 +209,24 @@ describe('OpenCodeInstallProvider — integration', () => {
199
209
  }
200
210
  });
201
211
 
202
- it('creates AGENTS.md with @-references', async () => {
212
+ it('creates AGENTS.md with embedded protocol', async () => {
203
213
  await install.ensureInstructionReferences(testDir);
204
214
  const content = readFileSync(join(testDir, 'AGENTS.md'), 'utf-8');
205
- // Structure check: must be a non-empty @~/... path pointing to CLEO-INJECTION.md (OS-agnostic)
206
- expect(content).toMatch(/@~\/.+\/CLEO-INJECTION\.md/);
207
- expect(content).toContain('@.cleo/memory-bridge.md');
215
+ expect(content).toContain('Fixture protocol: inspect authority and coverage.');
216
+ expect(content).toContain('Project memory bridge unavailable.');
217
+ expect(content).not.toContain('@.cleo/memory-bridge.md');
208
218
  });
209
219
 
210
- it('appends missing references to existing AGENTS.md', async () => {
220
+ it('embeds protocol while preserving existing AGENTS.md', async () => {
211
221
  const existing = '# Project Agents\n\nSome content.\n';
212
222
  writeFileSync(join(testDir, 'AGENTS.md'), existing, 'utf-8');
213
223
 
214
224
  await install.ensureInstructionReferences(testDir);
215
225
  const content = readFileSync(join(testDir, 'AGENTS.md'), 'utf-8');
216
226
  expect(content).toContain('# Project Agents');
217
- // Structure check: must be a non-empty @~/... path pointing to CLEO-INJECTION.md (OS-agnostic)
218
- expect(content).toMatch(/@~\/.+\/CLEO-INJECTION\.md/);
219
- expect(content).toContain('@.cleo/memory-bridge.md');
227
+ expect(content).toContain('Fixture protocol: inspect authority and coverage.');
228
+ expect(content).toContain('Project memory bridge unavailable.');
229
+ expect(content).not.toContain('@.cleo/memory-bridge.md');
220
230
  });
221
231
 
222
232
  it('does not duplicate CAAMP block on repeated calls', async () => {
@@ -231,6 +241,7 @@ describe('OpenCodeInstallProvider — integration', () => {
231
241
  const afterSecond = readFileSync(join(testDir, 'AGENTS.md'), 'utf-8');
232
242
  const blockCountSecond = (afterSecond.match(/<!-- CAAMP:START -->/g) ?? []).length;
233
243
  expect(blockCountSecond).toBe(1);
244
+ expect(afterSecond).toBe(afterFirst);
234
245
  });
235
246
 
236
247
  it('install returns expected shape', async () => {
@@ -17,7 +17,7 @@
17
17
  * @epic T1000
18
18
  */
19
19
 
20
- import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
20
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
21
21
  import { tmpdir } from 'node:os';
22
22
  import { join } from 'node:path';
23
23
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
@@ -39,6 +39,11 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
39
39
  process.env.HOME = fakeHome;
40
40
  process.env.USERPROFILE = fakeHome;
41
41
  process.env.CLAUDE_HOME = join(fakeHome, '.claude');
42
+ mkdirSync(join(fakeHome, '.cleo', 'templates'), { recursive: true });
43
+ writeFileSync(
44
+ join(fakeHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
45
+ 'Fixture protocol: inspect authority and coverage.',
46
+ );
42
47
  });
43
48
 
44
49
  afterEach(() => {
@@ -15,10 +15,10 @@
15
15
  * @epic T1000
16
16
  */
17
17
 
18
- import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
18
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
19
19
  import { tmpdir } from 'node:os';
20
20
  import { join } from 'node:path';
21
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
21
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
22
22
  import { CursorInstallProvider } from '../install.js';
23
23
 
24
24
  describe('CursorInstallProvider — PreCompact hook templates', () => {
@@ -26,9 +26,19 @@ describe('CursorInstallProvider — PreCompact hook templates', () => {
26
26
 
27
27
  beforeEach(() => {
28
28
  projectDir = mkdtempSync(join(tmpdir(), 'cleo-cursor-install-'));
29
+ const fixtureHome = join(projectDir, 'fixture-home');
30
+ vi.stubEnv('HOME', fixtureHome);
31
+ vi.stubEnv('USERPROFILE', fixtureHome);
32
+ vi.stubEnv('CLEO_HOME', join(fixtureHome, '.cleo'));
33
+ mkdirSync(join(fixtureHome, '.cleo', 'templates'), { recursive: true });
34
+ writeFileSync(
35
+ join(fixtureHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
36
+ 'Fixture protocol: inspect authority and coverage.',
37
+ );
29
38
  });
30
39
 
31
40
  afterEach(() => {
41
+ vi.unstubAllEnvs();
32
42
  rmSync(projectDir, { recursive: true, force: true });
33
43
  });
34
44
 
@@ -13,10 +13,10 @@
13
13
  * @epic T1000
14
14
  */
15
15
 
16
- import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
16
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
17
17
  import { tmpdir } from 'node:os';
18
18
  import { join } from 'node:path';
19
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
19
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
20
20
  import { OpenCodeInstallProvider } from '../install.js';
21
21
 
22
22
  describe('OpenCodeInstallProvider — PreCompact hook templates', () => {
@@ -24,9 +24,19 @@ describe('OpenCodeInstallProvider — PreCompact hook templates', () => {
24
24
 
25
25
  beforeEach(() => {
26
26
  projectDir = mkdtempSync(join(tmpdir(), 'cleo-opencode-install-'));
27
+ const fixtureHome = join(projectDir, 'fixture-home');
28
+ vi.stubEnv('HOME', fixtureHome);
29
+ vi.stubEnv('USERPROFILE', fixtureHome);
30
+ vi.stubEnv('CLEO_HOME', join(fixtureHome, '.cleo'));
31
+ mkdirSync(join(fixtureHome, '.cleo', 'templates'), { recursive: true });
32
+ writeFileSync(
33
+ join(fixtureHome, '.cleo', 'templates', 'CLEO-INJECTION.md'),
34
+ 'Fixture protocol: inspect authority and coverage.',
35
+ );
27
36
  });
28
37
 
29
38
  afterEach(() => {
39
+ vi.unstubAllEnvs();
30
40
  rmSync(projectDir, { recursive: true, force: true });
31
41
  });
32
42