clementine-agent 1.18.159 → 1.18.160
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/dist/cli/dashboard.js +42 -38
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -21,7 +21,11 @@ import { discoverMcpServers, getClaudeIntegrations, KNOWN_MCP_DESCRIPTIONS } fro
|
|
|
21
21
|
import { buildBuilderEnrichedMessage, builderSessionKey } from '../dashboard/builder/prompt.js';
|
|
22
22
|
import { AGENTS_DIR, MEMORY_FILE, SESSIONS_FILE, applyOneMillionContextRecovery, looksLikeClaudeOneMillionContextError, normalizeClaudeSdkOptionsForOneMillionContext, } from '../config.js';
|
|
23
23
|
import { parseTasks } from '../tools/shared.js';
|
|
24
|
-
|
|
24
|
+
// 1.18.160 — also pull parseCronJobs + parseAgentCronJobs so getCronJobs()
|
|
25
|
+
// returns the same merged set the runtime fires (CRON.md + agent CRON +
|
|
26
|
+
// schedule registry). Was reading only CRON.md before, hiding migrated
|
|
27
|
+
// scheduled-skills from the Tasks tab while they kept firing on schedule.
|
|
28
|
+
import { todayISO, CronRunLog, parseCronJobs, parseAgentCronJobs } from '../gateway/cron-scheduler.js';
|
|
25
29
|
import { goalsRouter } from './routes/goals.js';
|
|
26
30
|
import { delegationsRouter } from './routes/delegations.js';
|
|
27
31
|
import { workflowsRouter } from './routes/workflows.js';
|
|
@@ -1270,43 +1274,29 @@ function getSessions() {
|
|
|
1270
1274
|
}
|
|
1271
1275
|
}
|
|
1272
1276
|
function getCronJobs() {
|
|
1273
|
-
|
|
1274
|
-
//
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
//
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
continue;
|
|
1292
|
-
try {
|
|
1293
|
-
const raw = readFileSync(agentCronFile, 'utf-8');
|
|
1294
|
-
const parsed = matter(raw);
|
|
1295
|
-
const agentJobs = (parsed.data.jobs ?? []);
|
|
1296
|
-
for (const job of agentJobs) {
|
|
1297
|
-
jobs.push({ ...job, agent: slug, name: `${slug}:${job.name}` });
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
catch { /* ignore individual agent parse errors */ }
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
catch { /* ignore */ }
|
|
1304
|
-
}
|
|
1277
|
+
// 1.18.160 — delegate to the canonical merger so scheduled-skill rows
|
|
1278
|
+
// (from ~/.clementine/schedules.json) reach the dashboard alongside
|
|
1279
|
+
// legacy CRON.md entries. Before this, getCronJobs() only read CRON.md
|
|
1280
|
+
// — so when a user migrated 14 of their 15 crons to scheduled-skills,
|
|
1281
|
+
// the Tasks page silently dropped to 1 card while the runtime kept
|
|
1282
|
+
// firing all 22 jobs. The result LOOKED like a regression because the
|
|
1283
|
+
// user couldn't see, edit, pause, or trace any of the migrated work
|
|
1284
|
+
// from the Tasks tab. parseCronJobs() reads BOTH CRON.md + agent CRON
|
|
1285
|
+
// files + the schedule registry, dedups by name (scheduled-skill wins
|
|
1286
|
+
// collisions), and stamps `source` so the existing card renderer can
|
|
1287
|
+
// branch on SKILL vs LEGACY CRON badge.
|
|
1288
|
+
//
|
|
1289
|
+
// The dashboard now sees exactly what the runtime fires — single
|
|
1290
|
+
// source of truth, no drift. Both helpers are imported at the top.
|
|
1291
|
+
const allJobs = [
|
|
1292
|
+
...parseCronJobs(),
|
|
1293
|
+
...parseAgentCronJobs(path.join(VAULT_DIR, '00-System', 'agents')),
|
|
1294
|
+
];
|
|
1305
1295
|
// Attach recent run history. Single source of truth via CronRunLog.readRecent
|
|
1306
1296
|
// — same path the new /api/cron/runs cross-job endpoint uses, so per-card
|
|
1307
1297
|
// last-run and the Recent History zone never disagree.
|
|
1308
1298
|
const log = new CronRunLog();
|
|
1309
|
-
const enriched =
|
|
1299
|
+
const enriched = allJobs.map((job) => {
|
|
1310
1300
|
const name = String(job.name ?? '');
|
|
1311
1301
|
const recentRuns = log.readRecent(name, 10);
|
|
1312
1302
|
return { ...job, recentRuns };
|
|
@@ -27344,15 +27334,29 @@ async function refreshCron() {
|
|
|
27344
27334
|
// (definition.source !== 'scheduled-skill') and surfaces a one-click
|
|
27345
27335
|
// bulk migrator. Dismissable; persists in localStorage so it doesn't
|
|
27346
27336
|
// nag on every refresh.
|
|
27337
|
+
// 1.18.160 — only nag for UNHEALTHY legacy crons. After the user
|
|
27338
|
+
// bulk-migrates 14 healthy ones, having a banner shout about the
|
|
27339
|
+
// 1 healthy survivor felt naggy. The user can still migrate healthy
|
|
27340
|
+
// ones at their leisure via per-row "→ Skill" buttons; the banner
|
|
27341
|
+
// earns the screen real estate only when there's a real problem.
|
|
27347
27342
|
var legacyCount = 0;
|
|
27343
|
+
var legacyUnhealthyCount = 0;
|
|
27348
27344
|
try {
|
|
27349
|
-
|
|
27345
|
+
var legacyRows = (visibleTasks || []).filter(function(t) {
|
|
27350
27346
|
return !(t.definition && t.definition.source === 'scheduled-skill');
|
|
27347
|
+
});
|
|
27348
|
+
legacyCount = legacyRows.length;
|
|
27349
|
+
legacyUnhealthyCount = legacyRows.filter(function(t) {
|
|
27350
|
+
var h = t.health;
|
|
27351
|
+
return h === 'failed' || h === 'broken' || h === 'never_run';
|
|
27351
27352
|
}).length;
|
|
27352
27353
|
} catch (_) { /* defensive */ }
|
|
27353
27354
|
var bannerHtml = '';
|
|
27354
27355
|
var dismissed = localStorage.getItem('clem-skill-migrate-banner-dismissed') === '1';
|
|
27355
|
-
|
|
27356
|
+
// Show the banner only when there's an unhealthy legacy cron to nudge
|
|
27357
|
+
// the user about. Healthy legacy crons live quietly until the user
|
|
27358
|
+
// chooses to migrate them per-row.
|
|
27359
|
+
if (legacyUnhealthyCount > 0 && !dismissed) {
|
|
27356
27360
|
// 1.18.155 — data-banner-kind tags this as the legacy-cron soft-
|
|
27357
27361
|
// deprecation banner so refreshCronMigrateBanner can suppress its
|
|
27358
27362
|
// secondary "clean up preambles" banner when this one is showing
|
|
@@ -27360,8 +27364,8 @@ async function refreshCron() {
|
|
|
27360
27364
|
bannerHtml = '<div data-banner-kind="legacy-cron-soft-deprecation" style="background:rgba(124,58,237,0.08);border:1px solid var(--purple);border-radius:8px;padding:12px 14px;margin-bottom:14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap">'
|
|
27361
27365
|
+ '<span style="font-size:18px">⚡</span>'
|
|
27362
27366
|
+ '<div style="flex:1;min-width:200px">'
|
|
27363
|
-
+ '<div style="font-size:13px;font-weight:500;color:var(--text-primary)">' +
|
|
27364
|
-
+ '<div style="font-size:11px;color:var(--text-muted);margin-top:2px">
|
|
27367
|
+
+ '<div style="font-size:13px;font-weight:500;color:var(--text-primary)">' + legacyUnhealthyCount + ' legacy cron task' + (legacyUnhealthyCount === 1 ? '' : 's') + ' failing — migrating to a scheduled skill often clears the issue</div>'
|
|
27368
|
+
+ '<div style="font-size:11px;color:var(--text-muted);margin-top:2px">Scheduled skills use a tighter context envelope (lean mode for meta-jobs) and the Anthropic-canonical SKILL.md format. Healthy legacy crons stay quietly out of the way.</div>'
|
|
27365
27369
|
+ '</div>'
|
|
27366
27370
|
+ '<button class="btn-sm btn-primary" onclick="migrateAllCronsToSkills()" style="font-size:12px;padding:6px 12px">Migrate all eligible →</button>'
|
|
27367
27371
|
+ '<button class="btn-sm" onclick="localStorage.setItem(\\x27clem-skill-migrate-banner-dismissed\\x27,\\x271\\x27);refreshCron()" title="Hide this banner" style="font-size:12px;padding:6px 10px">Dismiss</button>'
|