@atollhq/skill-codex 0.4.9 → 0.4.10
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 +15 -5
- package/bin/install.mjs +145 -23
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/api-endpoints.md +1 -0
package/README.md
CHANGED
|
@@ -14,15 +14,25 @@ ATOLL_API_KEY=sk_atoll_... ATOLL_ORG_ID=your-org-id npx @atollhq/skill-codex@lat
|
|
|
14
14
|
|
|
15
15
|
Optional defaults: `--project`, `--team`, and `--base-url` are stored with the selected mode. Use `--no-project`, `--no-team`, or `--no-base-url` to clear previously saved defaults. Pass `--profile` to store credentials and defaults only in that named Atoll CLI profile. The installer does not write global `ATOLL_*` exports to `~/.zshrc` or `~/.bashrc` in profile mode. Use `atoll --profile agent-a ...` for profile-scoped commands, or omit `--profile` to use env-var mode.
|
|
16
16
|
|
|
17
|
+
For multi-org setups, keep global Codex instructions neutral and bind profiles per repo:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @atollhq/skill-codex@latest --profile agent-a --key sk_atoll_... --org your-org-id \
|
|
21
|
+
--write-project-instructions --project-dir /path/to/repo --instruction-files agents,claude
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`--write-project-instructions` writes a small managed block to repo-local instruction files. It requires `--profile`, defaults to the current directory, writes `AGENTS.md` by default, and can also write `CLAUDE.md` with `--instruction-files agents,claude`. If the target file already has unmanaged Atoll profile guidance, pass `--force-project-instructions` after reviewing the replacement.
|
|
25
|
+
|
|
17
26
|
Get an agent API key from **Agents** in the Atoll app. Integration keys are still managed from **Settings > Members**.
|
|
18
27
|
|
|
19
|
-
This does
|
|
28
|
+
This does six things:
|
|
20
29
|
|
|
21
30
|
1. Installs the `atoll-api` skill to `~/.codex/skills/atoll-api/`
|
|
22
|
-
2. Appends (or updates)
|
|
31
|
+
2. Appends (or updates) a neutral `# Atoll Integration` section in `~/.codex/AGENTS.md`
|
|
23
32
|
3. Copies API reference files to `~/.codex/atoll-references/`
|
|
24
33
|
4. Creates or updates the named Atoll CLI profile when `--profile` is provided
|
|
25
34
|
5. Appends Atoll env var exports to your shell profile (`~/.zshrc` or `~/.bashrc`) only when no profile is provided
|
|
35
|
+
6. Optionally writes repo-local profile guidance when `--write-project-instructions` is provided
|
|
26
36
|
|
|
27
37
|
For profile mode, Codex has the Atoll skill immediately and terminal commands can use `atoll --profile agent-a ...`. For env-var mode, the installer writes `ATOLL_ENV_MODE=1` with the credential exports; open a fresh shell or `source` your profile.
|
|
28
38
|
|
|
@@ -48,9 +58,9 @@ For terminal-first work, see [`@atollhq/cli`](https://www.npmjs.com/package/@ato
|
|
|
48
58
|
npm install -g @atollhq/cli
|
|
49
59
|
atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --project project-id --team team-id
|
|
50
60
|
atoll auth login --profile agent-a --key sk_atoll_... --org-id org-uuid --project project-id --no-team --no-base-url
|
|
51
|
-
atoll heartbeat
|
|
52
|
-
atoll issue list --json
|
|
53
|
-
atoll agent-context
|
|
61
|
+
atoll --profile agent-a heartbeat
|
|
62
|
+
atoll --profile agent-a issue list --json
|
|
63
|
+
atoll --profile agent-a agent-context
|
|
54
64
|
```
|
|
55
65
|
|
|
56
66
|
For multiple agents or orgs, use CLI auth profiles:
|
package/bin/install.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs'
|
|
4
|
-
import { join, dirname } from 'node:path'
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, statSync, renameSync, rmSync } from 'node:fs'
|
|
4
|
+
import { join, dirname, resolve, basename } from 'node:path'
|
|
5
5
|
import { homedir } from 'node:os'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
7
|
|
|
@@ -20,6 +20,10 @@ function parseArgs(argv) {
|
|
|
20
20
|
else if (argv[i] === '--no-team') args.clearTeam = true
|
|
21
21
|
else if (argv[i] === '--base-url' && argv[i + 1]) args.baseUrl = argv[++i]
|
|
22
22
|
else if (argv[i] === '--no-base-url') args.clearBaseUrl = true
|
|
23
|
+
else if (argv[i] === '--write-project-instructions') args.writeProjectInstructions = true
|
|
24
|
+
else if (argv[i] === '--project-dir' && argv[i + 1]) args.projectDir = argv[++i]
|
|
25
|
+
else if (argv[i] === '--instruction-files' && argv[i + 1]) args.instructionFiles = argv[++i]
|
|
26
|
+
else if (argv[i] === '--force-project-instructions') args.forceProjectInstructions = true
|
|
23
27
|
else if (argv[i] === '--help' || argv[i] === '-h') args.help = true
|
|
24
28
|
}
|
|
25
29
|
return args
|
|
@@ -40,12 +44,21 @@ Options:
|
|
|
40
44
|
--no-team Clear any saved default team.
|
|
41
45
|
--base-url Atoll base URL. Defaults to ATOLL_BASE_URL.
|
|
42
46
|
--no-base-url Clear any saved custom base URL.
|
|
47
|
+
--write-project-instructions
|
|
48
|
+
Write a small repo-local Atoll profile block. Requires --profile.
|
|
49
|
+
--project-dir
|
|
50
|
+
Directory for repo-local instructions. Defaults to the current directory.
|
|
51
|
+
--instruction-files
|
|
52
|
+
Comma-separated files to update: agents, claude, or agents,claude. Defaults to agents.
|
|
53
|
+
--force-project-instructions
|
|
54
|
+
Replace existing unmanaged Atoll profile guidance in repo-local instruction files.
|
|
43
55
|
--help Show this help message
|
|
44
56
|
|
|
45
57
|
Installs the Atoll integration for Codex CLI:
|
|
46
58
|
- Installs the atoll-api skill to ~/.codex/skills/atoll-api/
|
|
47
|
-
- Writes AGENTS.md
|
|
59
|
+
- Writes neutral AGENTS.md API guidance to ~/.codex/
|
|
48
60
|
- Creates/updates an Atoll CLI profile when --profile is provided
|
|
61
|
+
- Optionally writes repo-local AGENTS.md/CLAUDE.md profile guidance with --write-project-instructions
|
|
49
62
|
- Otherwise writes Atoll env vars to your shell profile for env-var mode
|
|
50
63
|
`)
|
|
51
64
|
}
|
|
@@ -64,6 +77,32 @@ if (args.help) { printUsage(); process.exit(0) }
|
|
|
64
77
|
|
|
65
78
|
console.log(`Running @atollhq/skill-codex installer v${packageJson.version}`)
|
|
66
79
|
|
|
80
|
+
const instructionFileChoices = (args.instructionFiles ?? 'agents')
|
|
81
|
+
.split(',')
|
|
82
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
83
|
+
.filter(Boolean)
|
|
84
|
+
const allowedInstructionFiles = new Set(['agents', 'claude'])
|
|
85
|
+
if (instructionFileChoices.some((entry) => !allowedInstructionFiles.has(entry))) {
|
|
86
|
+
console.error('Error: --instruction-files must be agents, claude, or agents,claude')
|
|
87
|
+
process.exit(1)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const projectInstructionFiles = [...new Set(instructionFileChoices)]
|
|
91
|
+
if (args.writeProjectInstructions && projectInstructionFiles.length === 0) {
|
|
92
|
+
console.error('Error: --instruction-files must include agents, claude, or agents,claude')
|
|
93
|
+
process.exit(1)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (args.writeProjectInstructions && !args.profile) {
|
|
97
|
+
console.error('Error: --write-project-instructions requires --profile so the repo-local guidance can name a profile')
|
|
98
|
+
process.exit(1)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (args.writeProjectInstructions && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(args.profile)) {
|
|
102
|
+
console.error('Error: --write-project-instructions requires a profile name that starts with a letter or number and contains only letters, numbers, dots, underscores, or hyphens')
|
|
103
|
+
process.exit(1)
|
|
104
|
+
}
|
|
105
|
+
|
|
67
106
|
if (!args.key || !args.org) {
|
|
68
107
|
console.error('Error: provide --key and --org, or set ATOLL_API_KEY and ATOLL_ORG_ID\n')
|
|
69
108
|
printUsage()
|
|
@@ -104,7 +143,6 @@ function writeAtollProfile() {
|
|
|
104
143
|
else delete profile.defaultTeam
|
|
105
144
|
if (args.baseUrl) profile.baseUrl = args.baseUrl
|
|
106
145
|
else delete profile.baseUrl
|
|
107
|
-
config.activeProfile = args.profile
|
|
108
146
|
|
|
109
147
|
mkdirSync(atollDir, { recursive: true })
|
|
110
148
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n')
|
|
@@ -112,6 +150,107 @@ function writeAtollProfile() {
|
|
|
112
150
|
return configPath
|
|
113
151
|
}
|
|
114
152
|
|
|
153
|
+
const projectInstructionsStart = '<!-- ATOLL:PROJECT-INSTRUCTIONS:START -->'
|
|
154
|
+
const projectInstructionsEnd = '<!-- ATOLL:PROJECT-INSTRUCTIONS:END -->'
|
|
155
|
+
const projectInstructionsPattern = new RegExp(`${projectInstructionsStart}[\\s\\S]*?${projectInstructionsEnd}`)
|
|
156
|
+
|
|
157
|
+
function projectInstructionBlock(profileName) {
|
|
158
|
+
return `${projectInstructionsStart}
|
|
159
|
+
## Atoll
|
|
160
|
+
|
|
161
|
+
For this workspace, use Atoll CLI profile \`${profileName}\`:
|
|
162
|
+
|
|
163
|
+
\`\`\`bash
|
|
164
|
+
atoll --profile ${profileName} ...
|
|
165
|
+
\`\`\`
|
|
166
|
+
${projectInstructionsEnd}`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function removeUnmanagedAtollProfileGuidance(content) {
|
|
170
|
+
return content
|
|
171
|
+
.split('\n')
|
|
172
|
+
.filter((line) => !/atoll\s+--profile\s+\S+/i.test(line) && !/Atoll CLI profile/i.test(line))
|
|
173
|
+
.join('\n')
|
|
174
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
175
|
+
.trimEnd()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function buildProjectInstructionUpdate(targetPath, block) {
|
|
179
|
+
const existing = existsSync(targetPath) ? readFileSync(targetPath, 'utf-8') : ''
|
|
180
|
+
|
|
181
|
+
if (projectInstructionsPattern.test(existing)) {
|
|
182
|
+
return {
|
|
183
|
+
targetPath,
|
|
184
|
+
content: existing.replace(projectInstructionsPattern, block),
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (/atoll\s+--profile\s+\S+/i.test(existing) || /Atoll CLI profile/i.test(existing)) {
|
|
189
|
+
if (!args.forceProjectInstructions) {
|
|
190
|
+
console.error(`Error: ${targetPath} already contains unmanaged Atoll profile guidance. Re-run with --force-project-instructions to replace it.`)
|
|
191
|
+
process.exit(1)
|
|
192
|
+
}
|
|
193
|
+
const cleaned = removeUnmanagedAtollProfileGuidance(existing)
|
|
194
|
+
return {
|
|
195
|
+
targetPath,
|
|
196
|
+
content: cleaned ? `${cleaned}\n\n${block}\n` : `${block}\n`,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
targetPath,
|
|
202
|
+
content: existing.trimEnd() ? `${existing.trimEnd()}\n\n${block}\n` : `${block}\n`,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function writeProjectInstructionUpdates(updates) {
|
|
207
|
+
const prepared = []
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
for (const [index, { targetPath, content }] of updates.entries()) {
|
|
211
|
+
const tmpPath = join(dirname(targetPath), `.${basename(targetPath)}.atoll-${process.pid}-${Date.now()}-${index}.tmp`)
|
|
212
|
+
const normalized = content.endsWith('\n') ? content : `${content}\n`
|
|
213
|
+
writeFileSync(tmpPath, normalized, { flag: 'wx' })
|
|
214
|
+
prepared.push({ targetPath, tmpPath })
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const { targetPath, tmpPath } of prepared) {
|
|
218
|
+
renameSync(tmpPath, targetPath)
|
|
219
|
+
console.log(`Wrote Atoll project instructions to ${targetPath}`)
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
for (const { tmpPath } of prepared) {
|
|
223
|
+
if (existsSync(tmpPath)) rmSync(tmpPath, { force: true })
|
|
224
|
+
}
|
|
225
|
+
console.error(`Error: failed to write Atoll project instructions: ${error.message}`)
|
|
226
|
+
process.exit(1)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function writeProjectInstructions() {
|
|
231
|
+
if (!args.writeProjectInstructions) return
|
|
232
|
+
|
|
233
|
+
const projectDir = resolve(args.projectDir ?? process.cwd())
|
|
234
|
+
if (!existsSync(projectDir) || !statSync(projectDir).isDirectory()) {
|
|
235
|
+
console.error(`Error: --project-dir must be an existing directory: ${projectDir}`)
|
|
236
|
+
process.exit(1)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const block = projectInstructionBlock(args.profile)
|
|
240
|
+
const fileNames = {
|
|
241
|
+
agents: 'AGENTS.md',
|
|
242
|
+
claude: 'CLAUDE.md',
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const updates = []
|
|
246
|
+
for (const choice of projectInstructionFiles) {
|
|
247
|
+
const targetPath = join(projectDir, fileNames[choice])
|
|
248
|
+
updates.push(buildProjectInstructionUpdate(targetPath, block))
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
writeProjectInstructionUpdates(updates)
|
|
252
|
+
}
|
|
253
|
+
|
|
115
254
|
// 1. Install the Codex skill to ~/.codex/skills/atoll-api/
|
|
116
255
|
const codexDir = join(homedir(), '.codex')
|
|
117
256
|
mkdirSync(codexDir, { recursive: true })
|
|
@@ -126,27 +265,9 @@ console.log(`Installed Atoll skill to ${skillDest}`)
|
|
|
126
265
|
const skillMd = readFileSync(join(skillDir, 'SKILL.md'), 'utf-8')
|
|
127
266
|
// Strip YAML frontmatter for AGENTS.md
|
|
128
267
|
const body = skillMd.replace(/^---[\s\S]*?---\n*/, '')
|
|
129
|
-
const profileModeInstructions = args.profile ? `## Profile-scoped CLI configuration
|
|
130
|
-
|
|
131
|
-
This Codex install is scoped to Atoll CLI profile \`${args.profile}\`. No global \`ATOLL_API_KEY\`, \`ATOLL_ORG_ID\`, \`ATOLL_PROJECT\`, \`ATOLL_TEAM\`, or \`ATOLL_BASE_URL\` shell exports were written. Use \`atoll --profile ${args.profile} ...\` for direct Atoll CLI commands. Direct API snippets below use \`ATOLL_API_KEY\` / \`ATOLL_ORG_ID\` only when you intentionally choose env-var mode.
|
|
132
|
-
|
|
133
|
-
` : ''
|
|
134
|
-
const optionalCredentialLines = [
|
|
135
|
-
args.profile ? `- Atoll CLI profile: ${args.profile}` : null,
|
|
136
|
-
args.project ? `- Default project ID: ${args.project}` : null,
|
|
137
|
-
args.team ? `- Default team: ${args.team}` : null,
|
|
138
|
-
args.baseUrl ? `- Base URL: ${args.baseUrl}` : null,
|
|
139
|
-
].filter(Boolean).join('\n')
|
|
140
|
-
|
|
141
268
|
const agentsMd = `# Atoll Integration
|
|
142
269
|
|
|
143
|
-
${profileModeInstructions}
|
|
144
270
|
${body}
|
|
145
|
-
|
|
146
|
-
## Credentials
|
|
147
|
-
|
|
148
|
-
- API Key: ${args.profile ? `stored in Atoll CLI profile \`${args.profile}\`` : 'set as ATOLL_API_KEY environment variable'}
|
|
149
|
-
- Org ID: ${args.org}${optionalCredentialLines ? `\n${optionalCredentialLines}` : ''}
|
|
150
271
|
`
|
|
151
272
|
|
|
152
273
|
const agentsPath = join(codexDir, 'AGENTS.md')
|
|
@@ -193,10 +314,11 @@ if (args.profile) {
|
|
|
193
314
|
console.log(`Removed stale Atoll shell exports from ${profilePath}`)
|
|
194
315
|
}
|
|
195
316
|
writeAtollProfile()
|
|
317
|
+
writeProjectInstructions()
|
|
196
318
|
console.log('No Atoll shell exports were written.')
|
|
197
319
|
console.log(`Run profile-scoped commands with: atoll --profile ${args.profile} ...`)
|
|
198
320
|
console.log(`Verify the profile with: atoll --profile ${args.profile} agent-context --json`)
|
|
199
|
-
console.log(`\nDone! Codex has the Atoll skill installed, and the Atoll CLI profile "${args.profile}" is
|
|
321
|
+
console.log(`\nDone! Codex has the Atoll skill installed, and the Atoll CLI profile "${args.profile}" is configured.`)
|
|
200
322
|
process.exit(0)
|
|
201
323
|
}
|
|
202
324
|
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -186,7 +186,7 @@ CLI JSON conventions:
|
|
|
186
186
|
|
|
187
187
|
When a human asks you to help automate a KPI from a third-party API, use this Atoll skill. If the current agent environment does not have the `atoll-api` skill installed, tell the user to install it before continuing or use the Atoll CLI/MCP tools directly if they are available.
|
|
188
188
|
|
|
189
|
-
Agents may create draft syncs and validate proposed configs only after a human admin has allowlisted the exact destination host in Atoll. Human admins must review the draft in
|
|
189
|
+
Agents may create draft syncs and validate proposed configs only after a human admin has allowlisted the exact destination host in Atoll. Human admins must create or review the draft in Settings > Integrations > KPI syncs, edit supported request/extraction fields and secrets through structured UI, dry-run, publish, disable, or run-now with snapshot writing.
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
192
|
atoll kpi sync validate <kpi-id> \
|
|
@@ -203,6 +203,7 @@ Roles: `owner`, `admin`, `member`, `guest`.
|
|
|
203
203
|
| POST | `/api/orgs/{id}/kpis/{kpiId}/snapshots` | Record a snapshot |
|
|
204
204
|
| GET | `/api/orgs/{id}/kpi-http-sync-policy` | List exact-host KPI HTTP sync allowlist policy |
|
|
205
205
|
| POST | `/api/orgs/{id}/kpi-http-sync-policy` | Add an allowed exact host (human admin only) |
|
|
206
|
+
| GET | `/api/orgs/{id}/kpi-http-syncs` | List org-wide KPI HTTP sync review rows for Settings; admins get config/secret metadata, members get redacted status rows |
|
|
206
207
|
| GET | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | List KPI HTTP syncs |
|
|
207
208
|
| POST | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Create a draft KPI HTTP sync |
|
|
208
209
|
| PUT | `/api/orgs/{id}/kpis/{kpiId}/http-syncs` | Validate a proposed KPI HTTP sync config without storing or running it |
|