@cleocode/adapters 2026.5.37 → 2026.5.40

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.
@@ -2,8 +2,7 @@
2
2
  * Pi Install Provider
3
3
  *
4
4
  * Handles CLEO installation into Pi coding agent environments:
5
- * - Ensures AGENTS.md has CLEO @-references (project and global scope)
6
- * - Manages Pi settings.json to register CLEO extension path
5
+ * - Ensures AGENTS.md has CLEO @-references via CAAMP (project and global scope)
7
6
  *
8
7
  * Pi uses AGENTS.md (not CLAUDE.md) as its instruction file. The global
9
8
  * instruction file lives at `~/.pi/agent/AGENTS.md`; the project-level
@@ -13,42 +12,20 @@
13
12
  * environment variables, or by presence of `~/.pi/agent/` directory.
14
13
  *
15
14
  * @task T553
15
+ * @task T9019
16
16
  */
17
17
 
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
- import { homedir } from 'node:os';
20
18
  import { join } from 'node:path';
19
+ import { ensureProviderInstructionFile } from '@cleocode/caamp';
21
20
  import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
22
21
  import { getCleoTemplatesTildePath } from '../shared/paths.js';
23
22
 
24
23
  /**
25
- * Lines that should appear in AGENTS.md to reference CLEO.
26
- * The CLEO-INJECTION.md path is resolved dynamically to support non-default
27
- * XDG / OS installation locations (T916).
24
+ * CLEO @-references injected into Pi instruction files.
25
+ * Resolved dynamically to support non-default XDG / OS installation locations (T916).
28
26
  */
29
- const INSTRUCTION_REFERENCES = [
30
- `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`,
31
- '@.cleo/memory-bridge.md',
32
- ];
33
-
34
- /**
35
- * Resolve the Pi global state root directory.
36
- *
37
- * Honours `PI_CODING_AGENT_DIR` env var when set (with `~` expansion),
38
- * then `PI_HOME`, then falls back to `~/.pi/agent`.
39
- */
40
- function getPiAgentDir(): string {
41
- const env = process.env['PI_CODING_AGENT_DIR'];
42
- if (env !== undefined && env.length > 0) {
43
- if (env === '~') return homedir();
44
- if (env.startsWith('~/')) return join(homedir(), env.slice(2));
45
- return env;
46
- }
47
- const piHome = process.env['PI_HOME'];
48
- if (piHome !== undefined && piHome.length > 0) {
49
- return join(piHome, 'agent');
50
- }
51
- return join(homedir(), '.pi', 'agent');
27
+ function getCleoReferences(): string[] {
28
+ return [`@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`, '@.cleo/memory-bridge.md'];
52
29
  }
53
30
 
54
31
  /**
@@ -56,7 +33,8 @@ function getPiAgentDir(): string {
56
33
  *
57
34
  * Manages CLEO's integration with Pi by:
58
35
  * 1. Ensuring project AGENTS.md contains @-references to CLEO instruction files
59
- * 2. Ensuring global AGENTS.md (~/.pi/agent/AGENTS.md) contains @-references
36
+ * (delegated to CAAMP's canonical {@link ensureProviderInstructionFile}).
37
+ * 2. Ensuring global AGENTS.md (~/.pi/agent/AGENTS.md) contains @-references.
60
38
  *
61
39
  * @remarks
62
40
  * Installation is idempotent — running install multiple times on the same
@@ -76,22 +54,31 @@ export class PiInstallProvider implements AdapterInstallProvider {
76
54
  const installedAt = new Date().toISOString();
77
55
  const details: Record<string, unknown> = {};
78
56
 
79
- // Step 1: Ensure project AGENTS.md has @-references
80
- const projectUpdated = this.updateInstructionFile(projectDir, 'AGENTS.md');
57
+ // Step 1: Ensure project AGENTS.md has @-references via CAAMP canonical API.
58
+ const projectResult = await ensureProviderInstructionFile('pi', projectDir, {
59
+ scope: 'project',
60
+ references: getCleoReferences(),
61
+ });
62
+
63
+ const projectUpdated = projectResult.action !== 'intact';
81
64
  if (projectUpdated) {
82
- details.instructionFile = join(projectDir, 'AGENTS.md');
65
+ details.instructionFile = join(projectDir, projectResult.instructFile);
83
66
  }
84
67
 
85
- // Step 2: Ensure global AGENTS.md has @-references (best-effort)
68
+ // Step 2: Ensure global AGENTS.md has @-references (best-effort).
69
+ // CAAMP resolves pathGlobal from the registry ($HOME/.pi/agent).
86
70
  let globalUpdated = false;
87
71
  try {
88
- const globalDir = getPiAgentDir();
89
- globalUpdated = this.updateInstructionFile(globalDir, 'AGENTS.md');
72
+ const globalResult = await ensureProviderInstructionFile('pi', projectDir, {
73
+ scope: 'global',
74
+ references: getCleoReferences(),
75
+ });
76
+ globalUpdated = globalResult.action !== 'intact';
90
77
  if (globalUpdated) {
91
- details.globalInstructionFile = join(globalDir, 'AGENTS.md');
78
+ details.globalInstructionFile = globalResult.filePath;
92
79
  }
93
80
  } catch {
94
- // Global install is best-effort — never block project install
81
+ // Global install is best-effort — never block project install.
95
82
  }
96
83
 
97
84
  const instructionFileUpdated = projectUpdated || globalUpdated;
@@ -114,30 +101,27 @@ export class PiInstallProvider implements AdapterInstallProvider {
114
101
  /**
115
102
  * Check whether CLEO is installed in the current environment.
116
103
  *
117
- * Checks for CLEO references in the project AGENTS.md.
104
+ * Delegates to CAAMP's instruction-file check for project and global scopes.
118
105
  */
119
106
  async isInstalled(): Promise<boolean> {
120
- const agentsMdPath = join(process.cwd(), 'AGENTS.md');
121
- if (existsSync(agentsMdPath)) {
122
- try {
123
- const content = readFileSync(agentsMdPath, 'utf-8');
124
- if (INSTRUCTION_REFERENCES.some((ref) => content.includes(ref))) {
125
- return true;
126
- }
127
- } catch {
128
- // Fall through
129
- }
107
+ // Check project-level AGENTS.md.
108
+ try {
109
+ const result = await ensureProviderInstructionFile('pi', process.cwd(), {
110
+ scope: 'project',
111
+ references: getCleoReferences(),
112
+ });
113
+ if (result.action === 'intact') return true;
114
+ } catch {
115
+ // Fall through
130
116
  }
131
117
 
132
- // Also check global AGENTS.md
118
+ // Also check global AGENTS.md.
133
119
  try {
134
- const globalPath = join(getPiAgentDir(), 'AGENTS.md');
135
- if (existsSync(globalPath)) {
136
- const content = readFileSync(globalPath, 'utf-8');
137
- if (INSTRUCTION_REFERENCES.some((ref) => content.includes(ref))) {
138
- return true;
139
- }
140
- }
120
+ const result = await ensureProviderInstructionFile('pi', process.cwd(), {
121
+ scope: 'global',
122
+ references: getCleoReferences(),
123
+ });
124
+ if (result.action === 'intact') return true;
141
125
  } catch {
142
126
  // Fall through
143
127
  }
@@ -148,50 +132,14 @@ export class PiInstallProvider implements AdapterInstallProvider {
148
132
  /**
149
133
  * Ensure AGENTS.md contains @-references to CLEO instruction files.
150
134
  *
151
- * Creates AGENTS.md if it does not exist. Appends any missing references.
135
+ * Delegates to CAAMP's canonical {@link ensureProviderInstructionFile}.
152
136
  *
153
137
  * @param projectDir - Project root directory
154
138
  */
155
139
  async ensureInstructionReferences(projectDir: string): Promise<void> {
156
- this.updateInstructionFile(projectDir, 'AGENTS.md');
157
- }
158
-
159
- /**
160
- * Update an instruction file with CLEO @-references.
161
- *
162
- * @param dir - Directory containing the instruction file
163
- * @param filename - Name of the instruction file (e.g. "AGENTS.md")
164
- * @returns true if the file was created or modified
165
- */
166
- private updateInstructionFile(dir: string, filename: string): boolean {
167
- const filePath = join(dir, filename);
168
- let content = '';
169
- let existed = false;
170
-
171
- if (existsSync(filePath)) {
172
- content = readFileSync(filePath, 'utf-8');
173
- existed = true;
174
- }
175
-
176
- const missingRefs = INSTRUCTION_REFERENCES.filter((ref) => !content.includes(ref));
177
-
178
- if (missingRefs.length === 0) {
179
- return false;
180
- }
181
-
182
- const refsBlock = missingRefs.join('\n');
183
-
184
- if (existed) {
185
- // Append missing references
186
- const separator = content.endsWith('\n') ? '' : '\n';
187
- content = content + separator + refsBlock + '\n';
188
- } else {
189
- // Create new file with references — ensure parent dir exists
190
- mkdirSync(dir, { recursive: true });
191
- content = refsBlock + '\n';
192
- }
193
-
194
- writeFileSync(filePath, content, 'utf-8');
195
- return true;
140
+ await ensureProviderInstructionFile('pi', projectDir, {
141
+ scope: 'project',
142
+ references: getCleoReferences(),
143
+ });
196
144
  }
197
145
  }