clementine-agent 1.18.158 → 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 +46 -43
- package/dist/cli/index.js +17 -19
- 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 };
|
|
@@ -1762,11 +1752,10 @@ export async function cmdDashboard(opts) {
|
|
|
1762
1752
|
if (process.env.NO_BROWSER !== '1') {
|
|
1763
1753
|
setTimeout(() => {
|
|
1764
1754
|
try {
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
const url = `http://localhost:${childPort}/?token=${token}`;
|
|
1755
|
+
// 1.18.159 — open the bare URL. Token comes from the meta tag
|
|
1756
|
+
// in the served HTML (persistent since 1.18.152). Bare URL also
|
|
1757
|
+
// sidesteps Chrome's per-query-string HTML cache entries.
|
|
1758
|
+
const url = `http://localhost:${childPort}`;
|
|
1770
1759
|
const platform = process.platform;
|
|
1771
1760
|
const cmd = platform === 'darwin' ? 'open'
|
|
1772
1761
|
: platform === 'win32' ? 'start'
|
|
@@ -27345,15 +27334,29 @@ async function refreshCron() {
|
|
|
27345
27334
|
// (definition.source !== 'scheduled-skill') and surfaces a one-click
|
|
27346
27335
|
// bulk migrator. Dismissable; persists in localStorage so it doesn't
|
|
27347
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.
|
|
27348
27342
|
var legacyCount = 0;
|
|
27343
|
+
var legacyUnhealthyCount = 0;
|
|
27349
27344
|
try {
|
|
27350
|
-
|
|
27345
|
+
var legacyRows = (visibleTasks || []).filter(function(t) {
|
|
27351
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';
|
|
27352
27352
|
}).length;
|
|
27353
27353
|
} catch (_) { /* defensive */ }
|
|
27354
27354
|
var bannerHtml = '';
|
|
27355
27355
|
var dismissed = localStorage.getItem('clem-skill-migrate-banner-dismissed') === '1';
|
|
27356
|
-
|
|
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) {
|
|
27357
27360
|
// 1.18.155 — data-banner-kind tags this as the legacy-cron soft-
|
|
27358
27361
|
// deprecation banner so refreshCronMigrateBanner can suppress its
|
|
27359
27362
|
// secondary "clean up preambles" banner when this one is showing
|
|
@@ -27361,8 +27364,8 @@ async function refreshCron() {
|
|
|
27361
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">'
|
|
27362
27365
|
+ '<span style="font-size:18px">⚡</span>'
|
|
27363
27366
|
+ '<div style="flex:1;min-width:200px">'
|
|
27364
|
-
+ '<div style="font-size:13px;font-weight:500;color:var(--text-primary)">' +
|
|
27365
|
-
+ '<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>'
|
|
27366
27369
|
+ '</div>'
|
|
27367
27370
|
+ '<button class="btn-sm btn-primary" onclick="migrateAllCronsToSkills()" style="font-size:12px;padding:6px 12px">Migrate all eligible →</button>'
|
|
27368
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>'
|
package/dist/cli/index.js
CHANGED
|
@@ -497,25 +497,23 @@ async function relaunchDashboardDetached(opts = {}) {
|
|
|
497
497
|
// print the URL. If it never binds, the URL still prints (user
|
|
498
498
|
// can retry) but we surface the failure in logs.
|
|
499
499
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
console.log(' Dashboard relaunched (token not ready — check `clementine status`).');
|
|
518
|
-
}
|
|
500
|
+
// 1.18.159 — print the bare URL, not the `?token=...` flavor.
|
|
501
|
+
// Token is delivered via meta tag in the served HTML (since 1.18.152
|
|
502
|
+
// when token persistence shipped). The token-in-URL flavor was a
|
|
503
|
+
// pre-1.18.152 habit and turned into a footgun: Chrome caches HTML
|
|
504
|
+
// by full URL including query string, so a stale `?token=ABC` cache
|
|
505
|
+
// entry survives across redeploys while bare `localhost:3030` pulls
|
|
506
|
+
// fresh HTML. Restart printing the bare URL also nudges users to
|
|
507
|
+
// bookmark THAT (which keeps working forever) instead of the
|
|
508
|
+
// token-flavored one (which would silently OK after a 1.18.152+
|
|
509
|
+
// restart but caches indefinitely on 1.18.151- installs).
|
|
510
|
+
const url = 'http://localhost:3030';
|
|
511
|
+
console.log(` Dashboard relaunched: ${url}`);
|
|
512
|
+
// 1.18.147 — auto-open the browser by default. Restart/update
|
|
513
|
+
// already imply user wants the dashboard back; making them copy a
|
|
514
|
+
// URL was a UX papercut.
|
|
515
|
+
if (opts.open !== false)
|
|
516
|
+
openInBrowser(url);
|
|
519
517
|
}
|
|
520
518
|
catch {
|
|
521
519
|
console.log(' Could not relaunch dashboard — run: clementine dashboard');
|