code-ai-installer 1.1.2 → 1.1.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.
- package/README.md +7 -2
- package/dist/contentTransformer.d.ts +0 -7
- package/dist/contentTransformer.js +28 -14
- package/dist/installer.js +1 -9
- package/dist/platforms/adapters.js +123 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,15 +80,20 @@ code-ai uninstall --target claude --apply
|
|
|
80
80
|
- Google Antugravity: `GEMINI.md`
|
|
81
81
|
- Agent files copied to target-specific agents directory.
|
|
82
82
|
- Skill files copied to target-specific skills directory.
|
|
83
|
+
- For `gpt-codex`, assets are installed to `agents/` and `.agents/` for native Codex discovery.
|
|
84
|
+
- For `google-antugravity`, assets are installed in antugravity-friendly structure:
|
|
85
|
+
- agents: `.gemini/agents/<agent>/prompt.md` and `.gemini/agents/<agent>/config.json`
|
|
86
|
+
- skills: `.gemini/skills/<skill>.md` and `.gemini/skills/<skill>.py`
|
|
87
|
+
- For `qwen-3.5`, installer also generates `.qwen/settings.json` with model/context defaults.
|
|
83
88
|
- Markdown content is normalized per target (model-specific hint comments like `codex:` are transformed).
|
|
84
|
-
- `codex reasoning` is mapped to target-native hints (`claude thinking`, `qwen reasoning_effort`, `gemini reasoning`).
|
|
89
|
+
- `codex reasoning` is mapped to target-native hints (`copilot reasoning`, `claude thinking`, `qwen reasoning_effort`, `gemini reasoning`).
|
|
85
90
|
|
|
86
91
|
## Safety model
|
|
87
92
|
- Default mode is `dry-run`.
|
|
88
93
|
- Backup is created before writes under `.code-ai-installer/backups/<target>/<timestamp>/`.
|
|
89
94
|
- State is tracked in `.code-ai-installer/state/<target>.json` for uninstall.
|
|
90
95
|
- Rollback restores previous files on install failure.
|
|
91
|
-
- Optional strict
|
|
96
|
+
- Optional strict adaptation mode: `--strict-hints` enforces target-hint emission and auto-fills missing hints with target defaults.
|
|
92
97
|
|
|
93
98
|
## Notes
|
|
94
99
|
- Target aliases are accepted: `copilot`, `codex`, `claude`, `qwen`, `google`, `antigravity`.
|
|
@@ -7,10 +7,3 @@ import type { TargetId } from "./types.js";
|
|
|
7
7
|
* @returns Target-normalized markdown content.
|
|
8
8
|
*/
|
|
9
9
|
export declare function transformContentForTarget(input: string, target: TargetId, assetType: "orchestrator" | "agent" | "skill"): string;
|
|
10
|
-
/**
|
|
11
|
-
* Returns whether markdown contains explicit hint for the selected target model.
|
|
12
|
-
* @param input Original markdown content.
|
|
13
|
-
* @param target Target AI identifier.
|
|
14
|
-
* @returns True when a native target hint is present.
|
|
15
|
-
*/
|
|
16
|
-
export declare function hasExplicitTargetHint(input: string, target: TargetId): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const hintRegex = /<!--\s*(codex|claude|qwen|gemini)\s*:\s*([\s\S]*?)-->\s*\n?/gi;
|
|
1
|
+
const hintRegex = /<!--\s*(codex|copilot|claude|qwen|gemini)\s*:\s*([\s\S]*?)-->\s*\n?/gi;
|
|
2
2
|
/**
|
|
3
3
|
* Transforms markdown content for selected AI target.
|
|
4
4
|
* @param input Original file content.
|
|
@@ -21,18 +21,6 @@ export function transformContentForTarget(input, target, assetType) {
|
|
|
21
21
|
const output = cleaned.trimStart();
|
|
22
22
|
return `${marker}${mappedHint}${output.endsWith("\n") ? output : `${output}\n`}`;
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Returns whether markdown contains explicit hint for the selected target model.
|
|
26
|
-
* @param input Original markdown content.
|
|
27
|
-
* @param target Target AI identifier.
|
|
28
|
-
* @returns True when a native target hint is present.
|
|
29
|
-
*/
|
|
30
|
-
export function hasExplicitTargetHint(input, target) {
|
|
31
|
-
const content = stripBom(input).replace(/\r\n/g, "\n");
|
|
32
|
-
const targetModel = targetToModel(target);
|
|
33
|
-
const hints = [...content.matchAll(/<!--\s*(codex|claude|qwen|gemini)\s*:\s*[\s\S]*?-->/gi)];
|
|
34
|
-
return hints.some((match) => String(match[1]).toLowerCase() === targetModel);
|
|
35
|
-
}
|
|
36
24
|
/**
|
|
37
25
|
* Returns content without UTF-8 BOM prefix.
|
|
38
26
|
* @param value Raw content.
|
|
@@ -66,17 +54,40 @@ function buildMappedHint(target, hints) {
|
|
|
66
54
|
}
|
|
67
55
|
const codex = hints.find((hint) => hint.model === "codex");
|
|
68
56
|
if (!codex) {
|
|
69
|
-
return
|
|
57
|
+
return `<!-- ${targetModel}: ${defaultPayloadForTarget(targetModel)} -->\n`;
|
|
70
58
|
}
|
|
71
59
|
const mappedPayload = mapCodexPayload(codex.payload, targetModel);
|
|
72
60
|
return `<!-- ${targetModel}: ${mappedPayload} -->\n`;
|
|
73
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Returns fallback payload when source markdown has no model hints.
|
|
64
|
+
* @param targetModel Destination model label.
|
|
65
|
+
* @returns Default target-model payload.
|
|
66
|
+
*/
|
|
67
|
+
function defaultPayloadForTarget(targetModel) {
|
|
68
|
+
if (targetModel === "copilot") {
|
|
69
|
+
return "reasoning=medium; note=\"auto-adapted default\"";
|
|
70
|
+
}
|
|
71
|
+
if (targetModel === "claude") {
|
|
72
|
+
return "thinking=medium; note=\"auto-adapted default\"";
|
|
73
|
+
}
|
|
74
|
+
if (targetModel === "qwen") {
|
|
75
|
+
return "reasoning_effort=medium; note=\"auto-adapted default\"";
|
|
76
|
+
}
|
|
77
|
+
if (targetModel === "gemini") {
|
|
78
|
+
return "reasoning=medium; note=\"auto-adapted default\"";
|
|
79
|
+
}
|
|
80
|
+
return "reasoning=medium; note=\"auto-adapted default\"";
|
|
81
|
+
}
|
|
74
82
|
/**
|
|
75
83
|
* Maps target id to hint model label.
|
|
76
84
|
* @param target Target AI identifier.
|
|
77
85
|
* @returns Target model name used in markdown hints.
|
|
78
86
|
*/
|
|
79
87
|
function targetToModel(target) {
|
|
88
|
+
if (target === "vscode-copilot") {
|
|
89
|
+
return "copilot";
|
|
90
|
+
}
|
|
80
91
|
if (target === "claude") {
|
|
81
92
|
return "claude";
|
|
82
93
|
}
|
|
@@ -110,6 +121,9 @@ function mapCodexPayload(payload, targetModel) {
|
|
|
110
121
|
const effort = mapReasoningToGemini(normalizedReasoning);
|
|
111
122
|
return withNote(`reasoning=${effort}`, note);
|
|
112
123
|
}
|
|
124
|
+
if (targetModel === "copilot") {
|
|
125
|
+
return withNote(`reasoning=${normalizedReasoning}`, note);
|
|
126
|
+
}
|
|
113
127
|
return withNote(`reasoning=${normalizedReasoning}`, note);
|
|
114
128
|
}
|
|
115
129
|
/**
|
package/dist/installer.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import fs from "fs-extra";
|
|
3
3
|
import { getPlatformAdapter } from "./platforms/adapters.js";
|
|
4
4
|
import { loadSourceCatalog } from "./catalog.js";
|
|
5
|
-
import {
|
|
5
|
+
import { transformContentForTarget } from "./contentTransformer.js";
|
|
6
6
|
/**
|
|
7
7
|
* Runs installation for selected target with optional dry-run and backup.
|
|
8
8
|
* @param options Install options.
|
|
@@ -105,14 +105,6 @@ async function applyOperations(args) {
|
|
|
105
105
|
continue;
|
|
106
106
|
}
|
|
107
107
|
let sourceContentForTransform;
|
|
108
|
-
if (operation.transform &&
|
|
109
|
-
args.strictHints &&
|
|
110
|
-
(operation.transform.assetType === "agent" || operation.transform.assetType === "skill")) {
|
|
111
|
-
sourceContentForTransform = await fs.readFile(operation.sourcePath, "utf8");
|
|
112
|
-
if (!hasExplicitTargetHint(sourceContentForTransform, operation.transform.target)) {
|
|
113
|
-
throw new Error(`Strict hints check failed: missing explicit '${operation.transform.target}' hint in ${operation.sourcePath}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
108
|
if (!args.dryRun && exists && backupDir) {
|
|
117
109
|
const rel = path.relative(args.destinationDir, destination);
|
|
118
110
|
const backupPath = path.join(backupDir, rel);
|
|
@@ -26,14 +26,14 @@ const targetLayouts = {
|
|
|
26
26
|
orchestratorMirrorFile: "AGENTS.md",
|
|
27
27
|
agentsDir: ".gemini/agents",
|
|
28
28
|
skillsDir: ".gemini/skills",
|
|
29
|
-
notes: "Uses GEMINI.md
|
|
29
|
+
notes: "Uses GEMINI.md and antugravity-style layout with per-agent folders and script-oriented skills.",
|
|
30
30
|
},
|
|
31
31
|
"gpt-codex": {
|
|
32
32
|
instructionFile: "CODEX.md",
|
|
33
33
|
orchestratorMirrorFile: "AGENTS.md",
|
|
34
|
-
agentsDir: "
|
|
35
|
-
skillsDir: ".
|
|
36
|
-
notes: "Uses
|
|
34
|
+
agentsDir: "agents",
|
|
35
|
+
skillsDir: ".agents",
|
|
36
|
+
notes: "Uses AGENTS.md/agents/.agents layout compatible with Codex agent and skills discovery.",
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
39
|
/**
|
|
@@ -100,6 +100,9 @@ function buildAdapter(id, label) {
|
|
|
100
100
|
* @returns Planned operations list.
|
|
101
101
|
*/
|
|
102
102
|
function planForLayout(layout, catalog, destinationDir, selectedAgents, selectedSkills, target) {
|
|
103
|
+
if (target === "google-antugravity") {
|
|
104
|
+
return planForGeminiLayout(layout, catalog, destinationDir, selectedAgents, selectedSkills, target);
|
|
105
|
+
}
|
|
103
106
|
const operations = [];
|
|
104
107
|
operations.push({
|
|
105
108
|
sourcePath: catalog.orchestratorPath,
|
|
@@ -117,6 +120,14 @@ function planForLayout(layout, catalog, destinationDir, selectedAgents, selected
|
|
|
117
120
|
generated: true,
|
|
118
121
|
content: instructionContent,
|
|
119
122
|
});
|
|
123
|
+
if (target === "qwen-3.5") {
|
|
124
|
+
operations.push({
|
|
125
|
+
sourcePath: "<generated>",
|
|
126
|
+
destinationPath: path.join(destinationDir, ".qwen", "settings.json"),
|
|
127
|
+
generated: true,
|
|
128
|
+
content: renderQwenSettings(),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
120
131
|
for (const agentName of selectedAgents) {
|
|
121
132
|
const sourcePath = catalog.agentFiles[agentName];
|
|
122
133
|
if (!sourcePath) {
|
|
@@ -149,6 +160,78 @@ function planForLayout(layout, catalog, destinationDir, selectedAgents, selected
|
|
|
149
160
|
}
|
|
150
161
|
return operations;
|
|
151
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Plans google-antugravity specific layout with per-agent folders and script-first skills.
|
|
165
|
+
* @param layout Platform layout.
|
|
166
|
+
* @param catalog Source catalog.
|
|
167
|
+
* @param destinationDir Destination root.
|
|
168
|
+
* @param selectedAgents Selected agent names.
|
|
169
|
+
* @param selectedSkills Selected skill names.
|
|
170
|
+
* @param target Target id.
|
|
171
|
+
* @returns Planned operations list.
|
|
172
|
+
*/
|
|
173
|
+
function planForGeminiLayout(layout, catalog, destinationDir, selectedAgents, selectedSkills, target) {
|
|
174
|
+
const operations = [];
|
|
175
|
+
operations.push({
|
|
176
|
+
sourcePath: catalog.orchestratorPath,
|
|
177
|
+
destinationPath: path.join(destinationDir, layout.orchestratorMirrorFile),
|
|
178
|
+
generated: false,
|
|
179
|
+
transform: {
|
|
180
|
+
target,
|
|
181
|
+
assetType: "orchestrator",
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
const instructionContent = renderInstructionFile(target, selectedAgents, selectedSkills);
|
|
185
|
+
operations.push({
|
|
186
|
+
sourcePath: "<generated>",
|
|
187
|
+
destinationPath: path.join(destinationDir, layout.instructionFile),
|
|
188
|
+
generated: true,
|
|
189
|
+
content: instructionContent,
|
|
190
|
+
});
|
|
191
|
+
for (const agentName of selectedAgents) {
|
|
192
|
+
const sourcePath = catalog.agentFiles[agentName];
|
|
193
|
+
if (!sourcePath) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
operations.push({
|
|
197
|
+
sourcePath,
|
|
198
|
+
destinationPath: path.join(destinationDir, layout.agentsDir, agentName, "prompt.md"),
|
|
199
|
+
generated: false,
|
|
200
|
+
transform: {
|
|
201
|
+
target,
|
|
202
|
+
assetType: "agent",
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
operations.push({
|
|
206
|
+
sourcePath: "<generated>",
|
|
207
|
+
destinationPath: path.join(destinationDir, layout.agentsDir, agentName, "config.json"),
|
|
208
|
+
generated: true,
|
|
209
|
+
content: renderGeminiAgentConfig(agentName),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
for (const skillName of selectedSkills) {
|
|
213
|
+
const sourcePath = catalog.skillFiles[skillName];
|
|
214
|
+
if (!sourcePath) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
operations.push({
|
|
218
|
+
sourcePath,
|
|
219
|
+
destinationPath: path.join(destinationDir, layout.skillsDir, `${skillName}.md`),
|
|
220
|
+
generated: false,
|
|
221
|
+
transform: {
|
|
222
|
+
target,
|
|
223
|
+
assetType: "skill",
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
operations.push({
|
|
227
|
+
sourcePath: "<generated>",
|
|
228
|
+
destinationPath: path.join(destinationDir, layout.skillsDir, `${skillName}.py`),
|
|
229
|
+
generated: true,
|
|
230
|
+
content: renderGeminiSkillStub(skillName),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return operations;
|
|
234
|
+
}
|
|
152
235
|
/**
|
|
153
236
|
* Renders a platform-level instruction file with selected assets.
|
|
154
237
|
* @param target Target id.
|
|
@@ -178,3 +261,39 @@ function renderInstructionFile(target, selectedAgents, selectedSkills) {
|
|
|
178
261
|
lines.push("- Skills: see platform-specific skills directory.");
|
|
179
262
|
return `${lines.join("\n")}\n`;
|
|
180
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Renders default antugravity agent config file.
|
|
266
|
+
* @param agentName Agent identifier.
|
|
267
|
+
* @returns Config JSON.
|
|
268
|
+
*/
|
|
269
|
+
function renderGeminiAgentConfig(agentName) {
|
|
270
|
+
return `${JSON.stringify({
|
|
271
|
+
name: agentName,
|
|
272
|
+
model: "gemini-2.5-pro",
|
|
273
|
+
promptFile: "prompt.md",
|
|
274
|
+
reasoning: "medium",
|
|
275
|
+
temperature: 0.2,
|
|
276
|
+
}, null, 2)}\n`;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Renders python stub for gemini skill file.
|
|
280
|
+
* @param skillName Skill identifier.
|
|
281
|
+
* @returns Python source code.
|
|
282
|
+
*/
|
|
283
|
+
function renderGeminiSkillStub(skillName) {
|
|
284
|
+
return `\"\"\"Auto-generated skill stub for ${skillName}.\\nSee ${skillName}.md for behavior details.\"\"\"\\n\\n\\ndef run(input_text: str) -> str:\\n \"\"\"Execute ${skillName} skill logic.\"\"\"\\n return f\"${skillName}: {input_text}\"\\n`;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Renders default Qwen settings.json.
|
|
288
|
+
* @returns Qwen settings JSON.
|
|
289
|
+
*/
|
|
290
|
+
function renderQwenSettings() {
|
|
291
|
+
return `${JSON.stringify({
|
|
292
|
+
model: {
|
|
293
|
+
name: "qwen3-coder-plus",
|
|
294
|
+
},
|
|
295
|
+
context: {
|
|
296
|
+
fileName: ["QWEN.md", "AGENTS.md"],
|
|
297
|
+
},
|
|
298
|
+
}, null, 2)}\n`;
|
|
299
|
+
}
|