thepopebot 1.2.75-beta.7 → 1.2.75-beta.8
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/bin/cli.js +10 -1
- package/config/instrumentation.js +3 -3
- package/lib/db/api-keys.js +5 -5
- package/lib/maintenance.js +29 -11
- package/lib/tools/docker.js +3 -3
- package/package.json +1 -1
- package/templates/skills/agent-job-secrets/SKILL.md +4 -4
- /package/templates/skills/agent-job-secrets/{agent-job-secrets.mjs → agent-job-secrets.js} +0 -0
package/bin/cli.js
CHANGED
|
@@ -248,6 +248,7 @@ async function init() {
|
|
|
248
248
|
const pkg = {
|
|
249
249
|
name: dirName,
|
|
250
250
|
private: true,
|
|
251
|
+
type: 'module',
|
|
251
252
|
scripts: {
|
|
252
253
|
setup: 'thepopebot setup',
|
|
253
254
|
'setup-telegram': 'thepopebot setup-telegram',
|
|
@@ -260,7 +261,15 @@ async function init() {
|
|
|
260
261
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
261
262
|
console.log(' Created package.json');
|
|
262
263
|
} else {
|
|
263
|
-
|
|
264
|
+
// Ensure "type": "module" is set for ESM support
|
|
265
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
266
|
+
if (!pkg.type) {
|
|
267
|
+
pkg.type = 'module';
|
|
268
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
269
|
+
console.log(' Added "type": "module" to package.json');
|
|
270
|
+
} else {
|
|
271
|
+
console.log(' Skipped package.json (already exists)');
|
|
272
|
+
}
|
|
264
273
|
}
|
|
265
274
|
|
|
266
275
|
// Create default skill activation symlinks
|
|
@@ -70,9 +70,9 @@ export async function register() {
|
|
|
70
70
|
const { startClusterRuntime } = await import('../lib/cluster/runtime.js');
|
|
71
71
|
startClusterRuntime();
|
|
72
72
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// Start internal maintenance cron (cleanup orphaned agent job keys, etc.)
|
|
74
|
+
const { startMaintenanceCron } = await import('../lib/maintenance.js');
|
|
75
|
+
startMaintenanceCron();
|
|
76
76
|
|
|
77
77
|
console.log('thepopebot initialized');
|
|
78
78
|
}
|
package/lib/db/api-keys.js
CHANGED
|
@@ -154,12 +154,12 @@ export function verifyApiKey(rawKey) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* Create a per-
|
|
158
|
-
* Stored as type 'agent_job_api_key'.
|
|
159
|
-
* @param {string}
|
|
157
|
+
* Create a per-container API key for agent secret access.
|
|
158
|
+
* Stored as type 'agent_job_api_key' with the container name in the key column.
|
|
159
|
+
* @param {string} containerName - Docker container name (used for cleanup)
|
|
160
160
|
* @returns {{ key: string }} The raw API key to inject into the container
|
|
161
161
|
*/
|
|
162
|
-
export function createAgentJobApiKey(
|
|
162
|
+
export function createAgentJobApiKey(containerName) {
|
|
163
163
|
const db = getDb();
|
|
164
164
|
const key = generateApiKey();
|
|
165
165
|
const keyHash = hashApiKey(key);
|
|
@@ -167,7 +167,7 @@ export function createAgentJobApiKey(jobId) {
|
|
|
167
167
|
db.insert(settings).values({
|
|
168
168
|
id: randomUUID(),
|
|
169
169
|
type: 'agent_job_api_key',
|
|
170
|
-
key:
|
|
170
|
+
key: containerName,
|
|
171
171
|
value: JSON.stringify({ key_hash: keyHash }),
|
|
172
172
|
createdAt: now,
|
|
173
173
|
updatedAt: now,
|
package/lib/maintenance.js
CHANGED
|
@@ -3,36 +3,54 @@ import { eq } from 'drizzle-orm';
|
|
|
3
3
|
import { getDb } from './db/index.js';
|
|
4
4
|
import { settings } from './db/schema.js';
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
|
7
7
|
|
|
8
|
-
function cleanExpiredAgentJobKeys() {
|
|
8
|
+
async function cleanExpiredAgentJobKeys() {
|
|
9
9
|
try {
|
|
10
10
|
const db = getDb();
|
|
11
|
-
const cutoff = Date.now() -
|
|
11
|
+
const cutoff = Date.now() - TWENTY_FOUR_HOURS;
|
|
12
12
|
const rows = db
|
|
13
|
-
.select({ id: settings.id, lastUsedAt: settings.lastUsedAt, createdAt: settings.createdAt })
|
|
13
|
+
.select({ id: settings.id, key: settings.key, lastUsedAt: settings.lastUsedAt, createdAt: settings.createdAt })
|
|
14
14
|
.from(settings)
|
|
15
15
|
.where(eq(settings.type, 'agent_job_api_key'))
|
|
16
16
|
.all();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
// Filter to candidates not used in the last 24 hours
|
|
19
|
+
const candidates = rows.filter(r =>
|
|
20
|
+
(r.lastUsedAt !== null ? r.lastUsedAt : r.createdAt) < cutoff
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (candidates.length === 0) {
|
|
24
|
+
console.log(`[maintenance] No expired agent job keys (${rows.length} active)`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Check if the container still exists for each candidate
|
|
29
|
+
const { inspectContainer } = await import('./tools/docker.js');
|
|
30
|
+
const expiredIds = [];
|
|
31
|
+
for (const r of candidates) {
|
|
32
|
+
const info = await inspectContainer(r.key);
|
|
33
|
+
if (!info) {
|
|
34
|
+
expiredIds.push(r.id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
if (expiredIds.length > 0) {
|
|
21
39
|
for (const id of expiredIds) {
|
|
22
40
|
db.delete(settings).where(eq(settings.id, id)).run();
|
|
23
41
|
}
|
|
24
|
-
console.log(`[maintenance] Deleted ${expiredIds.length}
|
|
42
|
+
console.log(`[maintenance] Deleted ${expiredIds.length} orphaned agent job key(s)`);
|
|
25
43
|
} else {
|
|
26
|
-
console.log(`[maintenance]
|
|
44
|
+
console.log(`[maintenance] ${candidates.length} candidate(s) checked, all containers still running`);
|
|
27
45
|
}
|
|
28
46
|
} catch (err) {
|
|
29
47
|
console.error('[maintenance] cleanExpiredAgentJobKeys failed:', err);
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
50
|
|
|
33
|
-
function runMaintenance() {
|
|
51
|
+
async function runMaintenance() {
|
|
34
52
|
console.log('[maintenance] Running maintenance...');
|
|
35
|
-
cleanExpiredAgentJobKeys();
|
|
53
|
+
await cleanExpiredAgentJobKeys();
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
export function startMaintenanceCron() {
|
package/lib/tools/docker.js
CHANGED
|
@@ -236,7 +236,7 @@ async function runInteractiveContainer({ containerName, repo, branch, codingAgen
|
|
|
236
236
|
}
|
|
237
237
|
// Create per-container API key for agent-secrets access
|
|
238
238
|
const { createAgentJobApiKey } = await import('../db/api-keys.js');
|
|
239
|
-
const { key: agentJobToken } = createAgentJobApiKey(
|
|
239
|
+
const { key: agentJobToken } = createAgentJobApiKey(containerName);
|
|
240
240
|
env.push(`AGENT_JOB_TOKEN=${agentJobToken}`);
|
|
241
241
|
const appUrl = getConfig('APP_URL');
|
|
242
242
|
if (appUrl) env.push(`APP_URL=${appUrl}`);
|
|
@@ -449,7 +449,7 @@ async function runHeadlessContainer({ containerName, repo, branch, featureBranch
|
|
|
449
449
|
}
|
|
450
450
|
// Create per-container API key for agent-secrets access
|
|
451
451
|
const { createAgentJobApiKey } = await import('../db/api-keys.js');
|
|
452
|
-
const { key: agentJobToken } = createAgentJobApiKey(
|
|
452
|
+
const { key: agentJobToken } = createAgentJobApiKey(containerName);
|
|
453
453
|
env.push(`AGENT_JOB_TOKEN=${agentJobToken}`);
|
|
454
454
|
const appUrl = getConfig('APP_URL');
|
|
455
455
|
if (appUrl) env.push(`APP_URL=${appUrl}`);
|
|
@@ -903,7 +903,7 @@ async function runAgentJobContainer({ agentJobId, repo, branch, title, descripti
|
|
|
903
903
|
|
|
904
904
|
// Create per-container API key for agent-secrets access
|
|
905
905
|
const { createAgentJobApiKey } = await import('../db/api-keys.js');
|
|
906
|
-
const { key: agentJobToken } = createAgentJobApiKey(
|
|
906
|
+
const { key: agentJobToken } = createAgentJobApiKey(containerName);
|
|
907
907
|
env.push(`AGENT_JOB_TOKEN=${agentJobToken}`);
|
|
908
908
|
|
|
909
909
|
// Inject agent job secrets (plain secrets as env vars; oauth types are null — agent must fetch via get)
|
package/package.json
CHANGED
|
@@ -7,14 +7,14 @@ description: List, get, or update agent secrets. Use get for OAuth credentials (
|
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
# List available secrets (null = must fetch, plain = already in env)
|
|
10
|
-
node skills/agent-job-secrets/agent-job-secrets.
|
|
10
|
+
node skills/agent-job-secrets/agent-job-secrets.js
|
|
11
11
|
|
|
12
12
|
# Get a secret value (OAuth credentials are auto-refreshed)
|
|
13
|
-
node skills/agent-job-secrets/agent-job-secrets.
|
|
13
|
+
node skills/agent-job-secrets/agent-job-secrets.js get MY_CREDENTIALS
|
|
14
14
|
|
|
15
15
|
# Set/update a secret (plain string or piped value)
|
|
16
|
-
node skills/agent-job-secrets/agent-job-secrets.
|
|
17
|
-
echo "$UPDATED_CREDENTIALS" | node skills/agent-job-secrets/agent-job-secrets.
|
|
16
|
+
node skills/agent-job-secrets/agent-job-secrets.js set MY_KEY "value"
|
|
17
|
+
echo "$UPDATED_CREDENTIALS" | node skills/agent-job-secrets/agent-job-secrets.js set MY_KEY
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Notes
|
|
File without changes
|