claude-code-session-manager 0.85.0 → 0.87.0
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/assets/AgentLibrary-DyLWzZDf.js +3 -0
- package/dist/assets/{DataModel-DRH-Ty20.js → DataModel--mISIJ6h.js} +1 -1
- package/dist/assets/{History-CfRhT1Im.js → History-C2ahUXTg.js} +2 -2
- package/dist/assets/{Hooks-wEmh_U6c.js → Hooks-BiC6oyR2.js} +3 -3
- package/dist/assets/{HostBilko-D_t7Rbi7.js → HostBilko-BPleEOld.js} +1 -1
- package/dist/assets/{Library-CpArQ-OJ.js → Library-Dc8Qst1R.js} +1 -1
- package/dist/assets/{ListDetail-pjaKYs84.js → ListDetail-DIXh-OLX.js} +1 -1
- package/dist/assets/MarkdownEditor-C90bkLXK.js +1 -0
- package/dist/assets/{McpServers-ftqaV3kn.js → McpServers-DqcbLOLZ.js} +2 -2
- package/dist/assets/{Memory-ChMWkNd0.js → Memory-CW62MXlh.js} +4 -4
- package/dist/assets/{Panel-D9Kr40Ai.js → Panel-Bw1FhRuF.js} +1 -1
- package/dist/assets/Permissions-BcUC-5y8.js +3 -0
- package/dist/assets/{Plugins-BtChISho.js → Plugins-BnKx9flD.js} +2 -2
- package/dist/assets/{ProvenanceBadge-DBA5EcYy.js → ProvenanceBadge-Bw5vNVPT.js} +1 -1
- package/dist/assets/{SaveBar-I0_dWNTX.js → SaveBar-CWr0O_w-.js} +1 -1
- package/dist/assets/Scheduler-DYdLuUqq.js +14 -0
- package/dist/assets/{ScopeSwitcher-5GTEveb2.js → ScopeSwitcher-CrBLbg8s.js} +1 -1
- package/dist/assets/Settings-DluB-vN1.js +3 -0
- package/dist/assets/{SkillReferenceGraph-DNBFGrYE.js → SkillReferenceGraph-CHLSseay.js} +1 -1
- package/dist/assets/{Skills-DJB6-bBM.js → Skills-gNdo_HNK.js} +2 -2
- package/dist/assets/{SystemPrompt-BiDDrJUA.js → SystemPrompt-Cru05-Ia.js} +1 -1
- package/dist/assets/{TagLibrary-_Wrevtop.js → TagLibrary-DNHY0xou.js} +1 -1
- package/dist/assets/{TiptapBody-OWWXdLRy.js → TiptapBody-I4lmbCgP.js} +1 -1
- package/dist/assets/{Toggle-B122N0HL.js → Toggle-bWMHjmRh.js} +1 -1
- package/dist/assets/{index-CDo9xBR9.css → index-DV3PorRY.css} +1 -1
- package/dist/assets/{index-DhvuQL4C.js → index-fc_JjdxL.js} +724 -724
- package/dist/assets/settingsSchema-BfhtZnGD.js +3 -0
- package/dist/index.html +2 -2
- package/package.json +15 -14
- package/plugins/CLAUDE.md +61 -0
- package/plugins/session-manager-dev/.claude-plugin/plugin.json +1 -1
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +1 -1
- package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +1 -1
- package/scripts/scheduler-mcp-server.cjs +7 -0
- package/src/main/__tests__/agentModelResolve.test.cjs +100 -9
- package/src/main/__tests__/broadcastCoalescer.test.cjs +18 -0
- package/src/main/__tests__/epicMint.test.cjs +2 -2
- package/src/main/__tests__/health-delegation-chain.test.cjs +2 -1
- package/src/main/__tests__/health-starve-escalation.test.cjs +94 -0
- package/src/main/__tests__/loadGateDetailTick.test.cjs +31 -0
- package/src/main/__tests__/machineProfile.test.cjs +19 -1
- package/src/main/__tests__/needsReviewLedger.test.cjs +162 -0
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +3 -3
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +15 -1
- package/src/main/__tests__/prdCreateDisposition.test.cjs +201 -0
- package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +125 -0
- package/src/main/__tests__/prdLocations.test.cjs +100 -2
- package/src/main/__tests__/prdLocationsArchived.test.cjs +43 -1
- package/src/main/__tests__/prdSetDisposition.test.cjs +222 -0
- package/src/main/__tests__/pty-session-open-telemetry.test.cjs +96 -0
- package/src/main/__tests__/queue-health-verdict.test.cjs +170 -0
- package/src/main/__tests__/queue-starvation-per-project.test.cjs +147 -0
- package/src/main/__tests__/queueHistory.test.cjs +63 -0
- package/src/main/__tests__/reconcileTiming.test.cjs +135 -0
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +101 -1
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +2 -2
- package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +121 -0
- package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +43 -0
- package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +121 -0
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +344 -0
- package/src/main/__tests__/scheduler-job-budget.test.cjs +172 -0
- package/src/main/__tests__/scheduler-looks-done.test.cjs +93 -3
- package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +189 -0
- package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +152 -0
- package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +164 -0
- package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +165 -0
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +160 -0
- package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +87 -0
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +88 -0
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +154 -0
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +14 -0
- package/src/main/__tests__/telemetryClient.test.cjs +75 -5
- package/src/main/__tests__/telemetrySettings.test.cjs +32 -0
- package/src/main/chatRunner.cjs +8 -5
- package/src/main/health.cjs +76 -3
- package/src/main/historyAggregator.cjs +5 -0
- package/src/main/index.cjs +95 -44
- package/src/main/ipcSchemas.cjs +47 -0
- package/src/main/lib/__tests__/active-sessions.test.cjs +251 -0
- package/src/main/lib/__tests__/bootSelfHeal.test.cjs +107 -0
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +322 -43
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +239 -0
- package/src/main/lib/__tests__/gitWorktree.test.cjs +89 -0
- package/src/main/lib/__tests__/guardShims.test.cjs +151 -0
- package/src/main/lib/__tests__/loadGate.test.cjs +103 -2
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +5 -5
- package/src/main/lib/__tests__/prdDisposition.test.cjs +224 -0
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +179 -1
- package/src/main/lib/__tests__/telemetryBoot.test.cjs +11 -0
- package/src/main/lib/__tests__/usageCircuit.test.cjs +224 -0
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +312 -0
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +193 -0
- package/{scripts → src/main}/lib/activeSessions.cjs +50 -4
- package/src/main/lib/agentModelResolve.cjs +65 -27
- package/src/main/lib/bootSelfHeal.cjs +88 -0
- package/src/main/lib/delegationReadiness.cjs +290 -225
- package/src/main/lib/effectiveModelInfo.cjs +333 -0
- package/src/main/lib/ephemeralCwd.cjs +1 -1
- package/src/main/lib/epicMint.cjs +3 -3
- package/src/main/lib/gitWorktree.cjs +42 -12
- package/src/main/lib/guardShims.cjs +156 -0
- package/src/main/lib/jobDirtFilter.cjs +7 -2
- package/src/main/lib/launchFailure.cjs +2 -1
- package/src/main/lib/loadGate.cjs +23 -1
- package/src/main/lib/machineProfile.cjs +15 -0
- package/src/main/lib/mcpToolCatalog.cjs +4 -1
- package/src/main/lib/needsReviewLedger.cjs +205 -0
- package/src/main/lib/opsErrorLog.cjs +1 -1
- package/src/main/lib/opsOwnership.cjs +1 -1
- package/src/main/lib/prdCreate.cjs +56 -1
- package/src/main/lib/prdDisposition.cjs +199 -0
- package/src/main/lib/prdFrontmatter.cjs +8 -2
- package/src/main/lib/prdLocations.cjs +167 -45
- package/src/main/lib/projectHomeAdminRoutes.cjs +4 -4
- package/src/main/lib/projectPageSummarySchema.cjs +1 -1
- package/src/main/lib/projectRootResolve.cjs +1 -1
- package/src/main/lib/queueHistory.cjs +19 -1
- package/src/main/lib/queueStore.cjs +6 -1
- package/src/main/lib/reaperHelpers.cjs +181 -15
- package/src/main/lib/scheduleJobSchema.cjs +8 -0
- package/src/main/lib/scheduleJobTransitions.cjs +33 -0
- package/src/main/lib/schedulerBatch.cjs +12 -1
- package/src/main/lib/schedulerConfig.cjs +37 -0
- package/src/main/lib/telemetryBoot.cjs +11 -8
- package/src/main/lib/telemetryClient.cjs +44 -2
- package/src/main/lib/telemetrySettings.cjs +20 -3
- package/src/main/lib/usageCircuit.cjs +159 -0
- package/{scripts → src/main}/lib/watchdogHelpers.cjs +1 -1
- package/src/main/pty.cjs +9 -0
- package/src/main/scheduler/prdParser.cjs +13 -0
- package/src/main/scheduler.cjs +1869 -193
- package/src/main/templates/PRD_AUTHORING.md +50 -0
- package/src/main/templates/project-pages-catalog.json +1 -1
- package/src/main/usage.cjs +21 -3
- package/src/preload/api.d.ts +92 -1
- package/src/preload/index.cjs +10 -0
- package/web/README.md +41 -0
- package/{scripts/render-project-pages.cjs → web/project-pages/render.cjs} +4 -4
- package/{scripts/render-project-pages → web/project-pages/renderer}/dist/renderer.cjs +1 -1
- package/{scripts/validate-project-pages-summary.cjs → web/project-pages/validate-summary.cjs} +5 -5
- package/dist/assets/AgentLibrary-Bkv-HcP1.js +0 -3
- package/dist/assets/MarkdownEditor-Xc141kjj.js +0 -1
- package/dist/assets/Permissions-DKoNVgzj.js +0 -3
- package/dist/assets/Scheduler-CbES7MC8.js +0 -14
- package/dist/assets/Settings-BX3FElXk.js +0 -3
- package/dist/assets/settingsSchema-sGoCTd7J.js +0 -3
- /package/{scripts/project-pages-logic → web/project-pages/logic}/dist/logic.cjs +0 -0
|
@@ -168,6 +168,38 @@ test('isMachineReportDue: true when lastMachineReportAt is more than 30 days bef
|
|
|
168
168
|
expect(telemetrySettings.isMachineReportDue(cfg, { now, appVersion: '0.81.0' })).toBe(true);
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
+
test('save() merges a partial patch onto a fresh disk read — concurrent savers do not clobber each other', async () => {
|
|
172
|
+
const home = await mkHome();
|
|
173
|
+
const telemetrySettings = await freshModule(home);
|
|
174
|
+
const base = await telemetrySettings.load(); // mints + persists installId
|
|
175
|
+
expect(base.installId).not.toBe('');
|
|
176
|
+
|
|
177
|
+
// Two independent writers, each stamping a DIFFERENT field, racing each
|
|
178
|
+
// other — mirrors telemetryBoot's install-report stamp landing around the
|
|
179
|
+
// same time as telemetryClient's own daily-flush stamp. Neither holds the
|
|
180
|
+
// other's snapshot; each passes only the field it intends to change.
|
|
181
|
+
await Promise.all([
|
|
182
|
+
telemetrySettings.save({ lastMachineReportAt: '2026-01-01T00:00:00.000Z', lastMachineReportVersion: '2.0.0' }),
|
|
183
|
+
telemetrySettings.save({ lastDailyFlushAt: '2026-01-01T01:00:00.000Z' }),
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
const onDisk = await telemetrySettings.load();
|
|
187
|
+
expect(onDisk.lastMachineReportAt).toBe('2026-01-01T00:00:00.000Z');
|
|
188
|
+
expect(onDisk.lastMachineReportVersion).toBe('2.0.0');
|
|
189
|
+
expect(onDisk.lastDailyFlushAt).toBe('2026-01-01T01:00:00.000Z');
|
|
190
|
+
// Neither save touched installId/enabled/endpoint — they must survive too.
|
|
191
|
+
expect(onDisk.installId).toBe(base.installId);
|
|
192
|
+
expect(onDisk.enabled).toBe(base.enabled);
|
|
193
|
+
expect(onDisk.endpoint).toBe(base.endpoint);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('save() rejects an unknown key without touching disk', async () => {
|
|
197
|
+
const home = await mkHome();
|
|
198
|
+
const telemetrySettings = await freshModule(home);
|
|
199
|
+
await telemetrySettings.load();
|
|
200
|
+
await expect(telemetrySettings.save({ notARealField: 'x' })).rejects.toThrow('Invalid telemetry config');
|
|
201
|
+
});
|
|
202
|
+
|
|
171
203
|
test('isMachineReportDue: false when same version and reported less than 30 days ago', async () => {
|
|
172
204
|
const home = await mkHome();
|
|
173
205
|
const telemetrySettings = await freshModule(home);
|
package/src/main/chatRunner.cjs
CHANGED
|
@@ -530,11 +530,14 @@ function executeRun({ tabId, sessionId, prompt, cwd, resume, silent, onSilentRes
|
|
|
530
530
|
const fullPrompt = STOP_SIGNAL_INSTRUCTION + CHAT_MODE_TRUTH_INSTRUCTION + prompt;
|
|
531
531
|
|
|
532
532
|
// sessionId is the Epic's claudeSessionId for an Epic-backed tab (see
|
|
533
|
-
// comment above childEnv) — resolve that Epic's agentType persona model
|
|
534
|
-
//
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
533
|
+
// comment above childEnv) — resolve that Epic's agentType persona model,
|
|
534
|
+
// project-overlay-then-global (agentModelResolve.cjs's
|
|
535
|
+
// readOverlayAwarePersonaModel). Terminal (EpicTerminalPane.tsx) calls
|
|
536
|
+
// this SAME function via the agents:resolve-epic-model IPC, so the two
|
|
537
|
+
// views of one Epic agree by construction, not by convention. Never
|
|
538
|
+
// throws; falls back to the hardcoded 'sonnet' literal when there's no
|
|
539
|
+
// Epic, no agentType, or the persona has no model/'inherit' — --model
|
|
540
|
+
// must never be left unpinned (CLAUDE.md model-pinning rule).
|
|
538
541
|
const model = agentModelResolve.resolveEpicModel({ cwd, claudeSessionId: sessionId });
|
|
539
542
|
|
|
540
543
|
// Build argv as an array — no shell: true, no string interpolation
|
package/src/main/health.cjs
CHANGED
|
@@ -16,9 +16,11 @@ const { checkDelegationReadiness } = require('./lib/delegationReadiness.cjs');
|
|
|
16
16
|
const { resolvePrdsDirs } = require('./lib/prdLocations.cjs');
|
|
17
17
|
const { migratePrds } = require('./lib/prdMigration.cjs');
|
|
18
18
|
const queueStore = require('./lib/queueStore.cjs');
|
|
19
|
-
const { computeStallSummary, SCHEDULER_STATE_PATH, FAILURE_STREAK_WARN_THRESHOLD, classifyQueueStarvation } = require('./scheduler.cjs');
|
|
19
|
+
const { computeStallSummary, SCHEDULER_STATE_PATH, FAILURE_STREAK_WARN_THRESHOLD, classifyQueueStarvation, STARVE_ESCALATION_MS } = require('./scheduler.cjs');
|
|
20
|
+
const { findStarvedProjects } = require('./lib/schedulerBatch.cjs');
|
|
21
|
+
const { AUDIT_LOG_PATH } = require('./lib/auditLog.cjs');
|
|
20
22
|
const { DEFAULT_RUNS_DIR, computeReport, isRetentionEnabled, liveKeysFromJobs } = require('./lib/runLogRetention.cjs');
|
|
21
|
-
const { allProjectCwds } = require('
|
|
23
|
+
const { allProjectCwds } = require('./lib/activeSessions.cjs');
|
|
22
24
|
|
|
23
25
|
const MAX_LOG_AGE_MS = 5 * 60_000; // 5 min — warn if no logs this old
|
|
24
26
|
const PROJECT_ROOT = path.resolve(__dirname, '../..');
|
|
@@ -458,6 +460,63 @@ function evaluateQueueDispatchHealth(queueState, runningCount, now, thresholdMs
|
|
|
458
460
|
};
|
|
459
461
|
}
|
|
460
462
|
|
|
463
|
+
/**
|
|
464
|
+
* latestStarveEscalationReasons(auditLogPath) → { [cwd]: holdReason }
|
|
465
|
+
*
|
|
466
|
+
* health.cjs runs as its own cold process (`npm run health`), so it has no
|
|
467
|
+
* access to the live scheduler's in-memory `lastTick` — the durable
|
|
468
|
+
* audit-log.jsonl trail (auditLog.cjs) is the only place the hold reason a
|
|
469
|
+
* 'project_starve_escalated' event already recorded (scheduler.cjs's
|
|
470
|
+
* runStarveEscalationSweep) survives to be read from here. Reads the SAME
|
|
471
|
+
* recorded value rather than re-deriving it; the last record per cwd wins.
|
|
472
|
+
* Missing/unreadable log → {} (no reasons known yet), never a throw.
|
|
473
|
+
*/
|
|
474
|
+
function latestStarveEscalationReasons(auditLogPath) {
|
|
475
|
+
let lines;
|
|
476
|
+
try {
|
|
477
|
+
lines = fs.readFileSync(auditLogPath, 'utf8').split('\n').filter(Boolean);
|
|
478
|
+
} catch {
|
|
479
|
+
return {};
|
|
480
|
+
}
|
|
481
|
+
const byCwd = {};
|
|
482
|
+
for (const line of lines) {
|
|
483
|
+
let rec;
|
|
484
|
+
try {
|
|
485
|
+
rec = JSON.parse(line);
|
|
486
|
+
} catch {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (rec?.kind === 'project_starve_escalated' && rec.cwd) byCwd[rec.cwd] = rec.holdReason ?? 'unknown';
|
|
490
|
+
}
|
|
491
|
+
return byCwd;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* evaluateStarveEscalationHealth(jobs, now, thresholdMs, escalationReasons)
|
|
496
|
+
* → { ok, projects?, message? }
|
|
497
|
+
*
|
|
498
|
+
* Pure over its inputs. Reuses findStarvedProjects — the exact per-cwd
|
|
499
|
+
* STARVED verdict the live escalation (scheduler.cjs) acts on — so health
|
|
500
|
+
* reports the identical set of starved-past-threshold projects, never a
|
|
501
|
+
* re-derived one. `escalationReasons` supplies the hold reason per cwd (see
|
|
502
|
+
* latestStarveEscalationReasons); a cwd with no recorded reason yet reports
|
|
503
|
+
* 'unknown' rather than failing.
|
|
504
|
+
*/
|
|
505
|
+
function evaluateStarveEscalationHealth(jobs, now, thresholdMs, escalationReasons = {}) {
|
|
506
|
+
const starved = findStarvedProjects(jobs, now, thresholdMs);
|
|
507
|
+
if (starved.length === 0) return { ok: true };
|
|
508
|
+
const projects = starved.map((sp) => ({
|
|
509
|
+
cwd: sp.cwd,
|
|
510
|
+
pendingCount: sp.pendingCount,
|
|
511
|
+
ageMs: sp.ageMs,
|
|
512
|
+
holdReason: escalationReasons[sp.cwd] ?? 'unknown',
|
|
513
|
+
}));
|
|
514
|
+
const message = `Project(s) starved past the ${Math.round(thresholdMs / 60_000)}m escalation threshold: ${
|
|
515
|
+
projects.map((p) => `${p.cwd} (${Math.round(p.ageMs / 60_000)}m, ${p.pendingCount} pending, hold=${p.holdReason})`).join('; ')
|
|
516
|
+
}`;
|
|
517
|
+
return { ok: false, projects, message };
|
|
518
|
+
}
|
|
519
|
+
|
|
461
520
|
function loadUsagePollerState(statePath) {
|
|
462
521
|
let raw;
|
|
463
522
|
try {
|
|
@@ -640,6 +699,18 @@ async function check() {
|
|
|
640
699
|
status.issues.push(`Queue dispatch: ${status.components.queue_dispatch.message}`);
|
|
641
700
|
}
|
|
642
701
|
|
|
702
|
+
// Per-project starve escalation (bounded consequence for project_starved
|
|
703
|
+
// — see runStarveEscalationSweep in scheduler.cjs). Distinct from
|
|
704
|
+
// queue_dispatch above: that's machine-wide dispatch liveness, this is
|
|
705
|
+
// "has any ONE project been starved past the LATER escalation threshold",
|
|
706
|
+
// the exact condition the 2026-09-12 19h Bilko starve went unreported by.
|
|
707
|
+
status.components.project_starve_escalation = evaluateStarveEscalationHealth(
|
|
708
|
+
queueState.jobs, now, STARVE_ESCALATION_MS, latestStarveEscalationReasons(AUDIT_LOG_PATH),
|
|
709
|
+
);
|
|
710
|
+
if (!status.components.project_starve_escalation.ok) {
|
|
711
|
+
status.issues.push(status.components.project_starve_escalation.message);
|
|
712
|
+
}
|
|
713
|
+
|
|
643
714
|
// Worktree cap blocking every dispatchable pending job with nothing
|
|
644
715
|
// running (see evaluateWorktreeCapBlocked's header) — a distinct
|
|
645
716
|
// condition from generic tick/dispatch staleness above, since a leaked
|
|
@@ -877,7 +948,7 @@ async function check() {
|
|
|
877
948
|
// Critical: nodejs, config dir, typescript, build artifact, test infrastructure.
|
|
878
949
|
// Non-fatal: scheduler/transcripts dirs may not exist on fresh install.
|
|
879
950
|
// Informational: app log age (shows if app is running, but not blocking).
|
|
880
|
-
const criticalComponents = ['nodejs', 'config_dir', 'typescript', 'build_artifact', 'test_infrastructure', 'scheduler_queue', 'queue_dispatch', 'usage_poller', 'prd_migration', 'claude_md_budget', 'delegation_chain'];
|
|
951
|
+
const criticalComponents = ['nodejs', 'config_dir', 'typescript', 'build_artifact', 'test_infrastructure', 'scheduler_queue', 'queue_dispatch', 'project_starve_escalation', 'usage_poller', 'prd_migration', 'claude_md_budget', 'delegation_chain'];
|
|
881
952
|
status.ok = criticalComponents.every((c) => status.components[c]?.ok !== false);
|
|
882
953
|
|
|
883
954
|
status.elapsedMs = Date.now() - start;
|
|
@@ -909,6 +980,8 @@ module.exports = {
|
|
|
909
980
|
evaluateUsagePollerHealth,
|
|
910
981
|
loadUsagePollerState,
|
|
911
982
|
evaluateQueueDispatchHealth,
|
|
983
|
+
evaluateStarveEscalationHealth,
|
|
984
|
+
latestStarveEscalationReasons,
|
|
912
985
|
DISPATCH_STALL_THRESHOLD_MS,
|
|
913
986
|
TICK_STALL_THRESHOLD_MS,
|
|
914
987
|
HEARTBEAT_STALE_MS,
|
|
@@ -21,10 +21,14 @@ const CACHE_MAX = 50_000;
|
|
|
21
21
|
// tokens are priced far below input because they're served from
|
|
22
22
|
// Anthropic's prompt cache, not re-processed — this is what makes the
|
|
23
23
|
// cache-savings figure in the dashboard real money, not a vanity stat.
|
|
24
|
+
// fable: Claude Fable 5.1 (claude-fable-5-1) — $10/$50 per MTok input/output,
|
|
25
|
+
// cache reads at $0.25/MTok (the `claude-api` skill's model reference and its
|
|
26
|
+
// Claude Fable 5.1 migration notes, both cached 2026-06-24).
|
|
24
27
|
const MODEL_PRICING = {
|
|
25
28
|
opus: { i: 15, o: 75, c: 1.5 },
|
|
26
29
|
sonnet: { i: 3, o: 15, c: 0.3 },
|
|
27
30
|
haiku: { i: 0.8, o: 4, c: 0.08 },
|
|
31
|
+
fable: { i: 10, o: 50, c: 0.25 },
|
|
28
32
|
};
|
|
29
33
|
const DEFAULT_PRICING_KEY = 'sonnet'; // fallback for unrecognized model ids
|
|
30
34
|
|
|
@@ -40,6 +44,7 @@ function resolvePricingKey(modelId) {
|
|
|
40
44
|
if (id.includes('opus')) return { key: 'opus', estimated: false };
|
|
41
45
|
if (id.includes('sonnet')) return { key: 'sonnet', estimated: false };
|
|
42
46
|
if (id.includes('haiku')) return { key: 'haiku', estimated: false };
|
|
47
|
+
if (id.includes('fable')) return { key: 'fable', estimated: false };
|
|
43
48
|
return { key: DEFAULT_PRICING_KEY, estimated: true };
|
|
44
49
|
}
|
|
45
50
|
|
package/src/main/index.cjs
CHANGED
|
@@ -37,7 +37,11 @@ const epicWorktreeMint = require('./lib/epicWorktreeMint.cjs');
|
|
|
37
37
|
const epicWorktreeMerge = require('./lib/epicWorktreeMerge.cjs');
|
|
38
38
|
const epicWorktreeProjectConfig = require('./lib/epicWorktreeProjectConfig.cjs');
|
|
39
39
|
const agentLibrary = require('./agentLibrary.cjs');
|
|
40
|
-
const
|
|
40
|
+
const agentModelResolve = require('./lib/agentModelResolve.cjs');
|
|
41
|
+
const { resolveEffectiveModelInfo } = require('./lib/effectiveModelInfo.cjs');
|
|
42
|
+
const { checkDelegationReadiness, ensureGuardsInstalled, installPrdWriteGuard, installDestructiveGitGuard, installInlineImplementationGuard } = require('./lib/delegationReadiness.cjs');
|
|
43
|
+
const { resolveProjectContext } = require('./lib/projectRootResolve.cjs');
|
|
44
|
+
const { writeGuardShims } = require('./lib/guardShims.cjs');
|
|
41
45
|
const { MCP_TOOL_CATALOG, MCP_RECIPES } = require('./lib/mcpToolCatalog.cjs');
|
|
42
46
|
const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
|
|
43
47
|
const { resolveBuildTarget } = require('./lib/buildTarget.cjs');
|
|
@@ -70,7 +74,7 @@ const telemetryConsent = require('./lib/telemetryConsent.cjs');
|
|
|
70
74
|
const { registerHistoryAggregatorHandlers, finalizeClosedDays, refreshIntradayToday } = require('./historyAggregator.cjs');
|
|
71
75
|
const runLogRetention = require('./lib/runLogRetention.cjs');
|
|
72
76
|
const { registerHistoryDashboardHandlers } = require('./historyDashboard.cjs');
|
|
73
|
-
const { tryAcquireLock, releaseLock, DEFAULT_LOCK_PATH } = require('
|
|
77
|
+
const { tryAcquireLock, releaseLock, DEFAULT_LOCK_PATH } = require('./lib/watchdogHelpers.cjs');
|
|
74
78
|
const schedulerConfig = require('./lib/schedulerConfig.cjs');
|
|
75
79
|
const memoryTool = require('./memoryTool.cjs');
|
|
76
80
|
const { registerMemoryAggregateIpc } = require('./memoryAggregate.cjs');
|
|
@@ -90,7 +94,8 @@ const { checkInsideHome, assertInsideHome } = require('./lib/insideHome.cjs');
|
|
|
90
94
|
const { openInEditor, openFileInEditor, openInFinder, openInTerminal } = require('./lib/openExternalApp.cjs');
|
|
91
95
|
const { rebuildActiveIndex } = require('./lib/activeIndexRebuild.cjs');
|
|
92
96
|
const { activeIndexPath: promptSessionsActiveIndexPath } = require('./lib/epicMint.cjs');
|
|
93
|
-
const { allProjectCwds } = require('
|
|
97
|
+
const { allProjectCwds } = require('./lib/activeSessions.cjs');
|
|
98
|
+
const { scheduleBootSelfHeal } = require('./lib/bootSelfHeal.cjs');
|
|
94
99
|
|
|
95
100
|
let mainWindow = null;
|
|
96
101
|
let rebooting = false;
|
|
@@ -520,12 +525,78 @@ ipcMain.handle('agents:remove-override', async (_e, payload) => {
|
|
|
520
525
|
ipcMain.handle('agents:get-persona-body', validated(schemas.agentsGetPersonaBody, (payload) =>
|
|
521
526
|
agentLibrary.getPersonaBody(payload)));
|
|
522
527
|
|
|
528
|
+
// "What will this Epic's launch actually use for --model?" — the SAME
|
|
529
|
+
// resolver chatRunner.cjs's Chat-view launch calls in-process
|
|
530
|
+
// (agentModelResolve.cjs's resolveEpicModel), reached here so Terminal's
|
|
531
|
+
// launch (EpicTerminalPane.tsx, a renderer module with no fs access) agrees
|
|
532
|
+
// with Chat by calling the identical function rather than a second one that
|
|
533
|
+
// is merely supposed to. Never throws (resolveEpicModel's own contract).
|
|
534
|
+
ipcMain.handle('agents:resolve-epic-model', validated(schemas.agentsResolveEpicModel, (payload) =>
|
|
535
|
+
agentModelResolve.resolveEpicModel(payload)));
|
|
536
|
+
|
|
537
|
+
// "What will this Epic actually run as?" (PRD: effective-model-resolver) —
|
|
538
|
+
// persona alias + evidence-based concrete model id + provenance, for a given
|
|
539
|
+
// (cwd, agentType). Read-only observer; never affects what a launch resolves.
|
|
540
|
+
ipcMain.handle('agents:resolve-model-info', validated(schemas.agentsResolveModelInfo, (payload) =>
|
|
541
|
+
resolveEffectiveModelInfo(payload)));
|
|
542
|
+
|
|
523
543
|
// "Can this project actually delegate?" probe (PRD: delegation-readiness).
|
|
524
544
|
// Structured data over the preconditions for scheduler_create_prd being in an
|
|
525
545
|
// agent's tool list at all — surfacing it in the UI is a sibling PRD.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
546
|
+
//
|
|
547
|
+
// Self-heals BEFORE computing the checks (PRD: guards-auto-install) — Fix It
|
|
548
|
+
// used to be the only call site for the three guard installers, so every
|
|
549
|
+
// project the human opened started red and demanded three manual clicks.
|
|
550
|
+
// ensureGuardsInstalled never rejects on its own, but it is still awaited
|
|
551
|
+
// inside a try/catch here so a future change to it can never turn this into
|
|
552
|
+
// a rejected IPC handler.
|
|
553
|
+
//
|
|
554
|
+
// `cwd` is normalized to its real project root via the SAME resolver
|
|
555
|
+
// prdAdminRoutes.cjs's session_manager_help readiness route already uses
|
|
556
|
+
// (projectRootResolve.cjs's resolveProjectContext) before either the install
|
|
557
|
+
// or the read-back check runs, so a worktree/ops-internal cwd can't install
|
|
558
|
+
// into one path while the banner reads another.
|
|
559
|
+
ipcMain.handle('app:delegation-readiness', validated(schemas.delegationReadinessCwd, async (payload) => {
|
|
560
|
+
const resolved = resolveProjectContext({ cwd: payload.cwd });
|
|
561
|
+
const cwd = resolved.cwd || payload.cwd;
|
|
562
|
+
try {
|
|
563
|
+
await ensureGuardsInstalled(cwd);
|
|
564
|
+
} catch { /* auto-install must never block the readiness probe itself */ }
|
|
565
|
+
return checkDelegationReadiness({ ...payload, cwd });
|
|
566
|
+
}));
|
|
567
|
+
|
|
568
|
+
// Every guard-install attempt is logged from MAIN, not the renderer — a
|
|
569
|
+
// press that never reaches this process (e.g. a renderer talking to an
|
|
570
|
+
// older main with no handler for the channel, Electron's own "No handler
|
|
571
|
+
// registered for ..." rejection) leaves no line here, which is exactly what
|
|
572
|
+
// makes it distinguishable from a press that reached main and failed. Uses
|
|
573
|
+
// opsErrorLog.appendError (the sole writer of the `logs` ops namespace) so
|
|
574
|
+
// the record lands in the project's own
|
|
575
|
+
// session-manager-operations/logs/errors-<date>.jsonl, same shape as every
|
|
576
|
+
// other structured error line.
|
|
577
|
+
function logGuardInstallAttempt(guard, cwd, outcome) {
|
|
578
|
+
const opsErrorLog = require('./lib/opsErrorLog.cjs');
|
|
579
|
+
opsErrorLog.appendError({
|
|
580
|
+
cwd,
|
|
581
|
+
scope: 'delegationReadinessGuardInstall',
|
|
582
|
+
level: outcome.ok ? 'info' : 'error',
|
|
583
|
+
message: outcome.ok
|
|
584
|
+
? `${guard} install ${outcome.action}`
|
|
585
|
+
: `${guard} install failed: ${outcome.error || 'unknown error'}`,
|
|
586
|
+
meta: { guard, ...outcome },
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async function handleGuardInstall(guard, installFn, payload) {
|
|
591
|
+
try {
|
|
592
|
+
const result = await installFn(payload);
|
|
593
|
+
logGuardInstallAttempt(guard, payload.cwd, result);
|
|
594
|
+
return result;
|
|
595
|
+
} catch (err) {
|
|
596
|
+
logGuardInstallAttempt(guard, payload.cwd, { ok: false, action: 'error', error: err?.message ?? String(err) });
|
|
597
|
+
throw err;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
529
600
|
|
|
530
601
|
// The three readiness checks with a sanctioned one-press install. Session
|
|
531
602
|
// Manager standardizes on the REFERENCE approach (absolute path to this
|
|
@@ -536,13 +607,13 @@ ipcMain.handle('app:delegation-readiness', validated(schemas.delegationReadiness
|
|
|
536
607
|
// header. inline-implementation-guard shares prd-write-guard's matcher, so
|
|
537
608
|
// its installer appends into that SAME matcher's `hooks` array instead.
|
|
538
609
|
ipcMain.handle('app:install-prd-write-guard', validated(schemas.delegationReadinessCwd, (payload) =>
|
|
539
|
-
installPrdWriteGuard
|
|
610
|
+
handleGuardInstall('prd-write-guard', installPrdWriteGuard, payload)
|
|
540
611
|
));
|
|
541
612
|
ipcMain.handle('app:install-destructive-git-guard', validated(schemas.delegationReadinessCwd, (payload) =>
|
|
542
|
-
installDestructiveGitGuard
|
|
613
|
+
handleGuardInstall('destructive-git-guard', installDestructiveGitGuard, payload)
|
|
543
614
|
));
|
|
544
615
|
ipcMain.handle('app:install-inline-implementation-guard', validated(schemas.delegationReadinessCwd, (payload) =>
|
|
545
|
-
installInlineImplementationGuard
|
|
616
|
+
handleGuardInstall('inline-implementation-guard', installInlineImplementationGuard, payload)
|
|
546
617
|
));
|
|
547
618
|
|
|
548
619
|
ipcMain.handle('app:engage-rules-path', () => process.env.SESSION_MANAGER_ENGAGE_RULES || null);
|
|
@@ -1274,42 +1345,22 @@ app.whenReady().then(async () => {
|
|
|
1274
1345
|
seedSchedulerMcp({ logger: console, writeLog: logs.writeLine }).catch((e) => {
|
|
1275
1346
|
logs.writeLine({ scope: 'seed-scheduler-mcp', level: 'error', message: 'seed failed', meta: { error: e?.message } });
|
|
1276
1347
|
});
|
|
1348
|
+
// Rewrite the stable guard-hook shims (~/.claude/session-manager/hooks/) to
|
|
1349
|
+
// point at THIS running app's root, on every boot. An already-installed
|
|
1350
|
+
// project hook resolves through the shim at invocation time, so an app
|
|
1351
|
+
// upgrade (a new npx hash dir) just follows along with no re-install — see
|
|
1352
|
+
// guardShims.cjs's header.
|
|
1353
|
+
writeGuardShims().catch((e) => {
|
|
1354
|
+
logs.writeLine({ scope: 'guard-shims', level: 'error', message: 'writeGuardShims failed', meta: { error: e?.message } });
|
|
1355
|
+
});
|
|
1277
1356
|
// Epic index self-heal: a project whose active-index.json is MISSING or
|
|
1278
1357
|
// fails to parse has lost every open Epic's status unless the per-Epic
|
|
1279
|
-
// status mirror (epicStatusMirror.cjs) can rebuild it. Runs once per boot
|
|
1280
|
-
//
|
|
1281
|
-
//
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
let unclean = false;
|
|
1286
|
-
let parseError = null;
|
|
1287
|
-
if (!fs.existsSync(indexPath)) {
|
|
1288
|
-
unclean = true;
|
|
1289
|
-
} else {
|
|
1290
|
-
try {
|
|
1291
|
-
JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
1292
|
-
} catch (e) {
|
|
1293
|
-
unclean = true;
|
|
1294
|
-
parseError = e.message;
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
if (!unclean) continue;
|
|
1298
|
-
try {
|
|
1299
|
-
const { rows, skipped } = rebuildActiveIndex(projectCwd);
|
|
1300
|
-
logs.writeLine({
|
|
1301
|
-
scope: 'active-index-rebuild',
|
|
1302
|
-
level: 'info',
|
|
1303
|
-
message: 'rebuilt active-index.json from status mirrors',
|
|
1304
|
-
meta: { cwd: projectCwd, parseError, restored: rows.length, skipped: skipped.length },
|
|
1305
|
-
});
|
|
1306
|
-
} catch (e) {
|
|
1307
|
-
logs.writeLine({ scope: 'active-index-rebuild', level: 'error', message: 'rebuild failed', meta: { cwd: projectCwd, error: e?.message } });
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
} catch (e) {
|
|
1311
|
-
logs.writeLine({ scope: 'active-index-rebuild', level: 'error', message: 'boot sweep failed', meta: { error: e?.message } });
|
|
1312
|
-
}
|
|
1358
|
+
// status mirror (epicStatusMirror.cjs) can rebuild it. Runs once per boot
|
|
1359
|
+
// and only touches a project whose index reads unclean — a clean index is
|
|
1360
|
+
// never rewritten. Deferred until the window paints (did-finish-load) so
|
|
1361
|
+
// the ~270ms allProjectCwds() scan doesn't compete with the renderer's
|
|
1362
|
+
// first IPC round trips for the event loop — see bootSelfHeal.cjs.
|
|
1363
|
+
scheduleBootSelfHeal(mainWindow, { fs, allProjectCwds, promptSessionsActiveIndexPath, rebuildActiveIndex, logs });
|
|
1313
1364
|
// History rollup finalize pass: deferred 30s past boot so it never competes
|
|
1314
1365
|
// with first-paint, fire-and-forget (cron/offline refresh is PRD 651 — this
|
|
1315
1366
|
// is just the one-shot in-app pass).
|
|
@@ -1340,7 +1391,7 @@ app.whenReady().then(async () => {
|
|
|
1340
1391
|
}, 30_000);
|
|
1341
1392
|
// Keep TODAY's rollup line current so the History dashboard never needs to
|
|
1342
1393
|
// fall back to a live transcript scan. Shares the same O_EXCL lock file as
|
|
1343
|
-
// the external watchdog's finalize pass (
|
|
1394
|
+
// the external watchdog's finalize pass (src/main/lib/watchdogHelpers.cjs)
|
|
1344
1395
|
// so the two never interleave writes to the rollup; a contended lock just
|
|
1345
1396
|
// means this tick's refresh is skipped (harmless — the next tick retries).
|
|
1346
1397
|
const intradayTimer = setInterval(runIntradayRefresh, schedulerConfig.HISTORY_INTRADAY_REFRESH_MS);
|
package/src/main/ipcSchemas.cjs
CHANGED
|
@@ -320,6 +320,11 @@ const PrdAgentTypeSchema = z.string().regex(PERSONA_NAME_RE, 'agent name must be
|
|
|
320
320
|
// call site since update also allows an explicit empty array to CLEAR the
|
|
321
321
|
// dependency, which create has no reason to accept.
|
|
322
322
|
const DepSlugSchema = z.string().min(1).max(160).regex(/^[A-Za-z0-9][\w.-]*$/);
|
|
323
|
+
// Wave-authoring decision (scheduler wave-disposition PRD), shared between
|
|
324
|
+
// schedulerCreatePrd (authoring time) and adminPrdFrontmatterPatch (the
|
|
325
|
+
// after-the-fact change path) so both can never disagree on what a valid
|
|
326
|
+
// disposition value is.
|
|
327
|
+
const PrdDispositionSchema = z.enum(['append', 'new-head']);
|
|
323
328
|
const schedulerCreatePrd = z.object({
|
|
324
329
|
title: z.string().min(1).max(200).regex(NO_NEWLINE_RE, 'must not contain newlines'),
|
|
325
330
|
// Optional (PRD: worktree-cwd Epic-lookup hazard) — when omitted, prdCreate.cjs's
|
|
@@ -340,6 +345,12 @@ const schedulerCreatePrd = z.object({
|
|
|
340
345
|
// Explicit ordering (PRD 832): slugs that must complete before this PRD
|
|
341
346
|
// becomes eligible. Written to frontmatter as `dependsOn: [a, b]`.
|
|
342
347
|
dependsOn: z.array(DepSlugSchema).max(20).optional(),
|
|
348
|
+
// Explicit wave-authoring decision (scheduler wave-disposition PRD) — only
|
|
349
|
+
// meaningful (and only stamped) when this PRD joins an Epic that already
|
|
350
|
+
// has incomplete PRDs and lands as a wave root (no dependsOn of its own);
|
|
351
|
+
// createPrd() requires it in that situation for an interactive caller and
|
|
352
|
+
// defaults to 'append' (logged as a default) for a non-interactive one.
|
|
353
|
+
disposition: PrdDispositionSchema.optional(),
|
|
343
354
|
// An EXISTING Epic's promptSessionId (PRD 748) — NOT a PromptTicket.id.
|
|
344
355
|
// ensureEpic() (epicMint.cjs) joins the Epic whose active-index.json
|
|
345
356
|
// sessions key literally equals this value; the renderer only ever sends
|
|
@@ -387,6 +398,19 @@ const schedulerCreatePrd = z.object({
|
|
|
387
398
|
quietMachine: z.boolean().optional(),
|
|
388
399
|
});
|
|
389
400
|
|
|
401
|
+
// Renderer-facing counterpart to adminPrdFrontmatterPatch's dependsOn/
|
|
402
|
+
// disposition patch (scheduler wave-disposition PRD) — backs the Scheduler
|
|
403
|
+
// UI's "change disposition" action. `dependsOn` is the caller's already-
|
|
404
|
+
// computed target (from the SAME backlog tree the UI renders — see
|
|
405
|
+
// lib/backlogTree.ts); the main-process handler only validates the rewrite
|
|
406
|
+
// is safe (prdDisposition.cjs), never re-derives "the" terminal itself.
|
|
407
|
+
const scheduleSetPrdDisposition = z.object({
|
|
408
|
+
slug: z.string().regex(SCHEDULE_SLUG_RE),
|
|
409
|
+
cwd: z.string().min(1).max(4096).optional(),
|
|
410
|
+
disposition: PrdDispositionSchema,
|
|
411
|
+
dependsOn: z.array(DepSlugSchema).max(20).optional(),
|
|
412
|
+
});
|
|
413
|
+
|
|
390
414
|
// Bulk archive: slug list, capped to limit unbounded retag/archive payloads.
|
|
391
415
|
// Optional cwd narrows every slug's directory search to one project (same
|
|
392
416
|
// role as scheduler_get_prd/scheduler_update_prd's cwd hint) — omitted, the
|
|
@@ -469,6 +493,11 @@ const adminPrdFrontmatterPatch = z.object({
|
|
|
469
493
|
// (depSlugResolve.cjs) scheduler_create_prd uses, so update and create
|
|
470
494
|
// can never disagree about what a dependsOn entry resolves to.
|
|
471
495
|
dependsOn: z.array(DepSlugSchema).max(20).optional(),
|
|
496
|
+
// Patchable after creation too — the Scheduler UI's "change disposition"
|
|
497
|
+
// action (promote a wave to its own head, or attach it behind another
|
|
498
|
+
// chain) rewrites this alongside dependsOn via the same
|
|
499
|
+
// schedule:set-prd-disposition path (see prdDisposition.cjs).
|
|
500
|
+
disposition: PrdDispositionSchema.optional(),
|
|
472
501
|
});
|
|
473
502
|
|
|
474
503
|
const adminUpdatePrd = z.object({
|
|
@@ -623,6 +652,21 @@ const agentsGetPersonaBody = z.object({
|
|
|
623
652
|
name: z.string().min(1).max(200),
|
|
624
653
|
}).strict();
|
|
625
654
|
|
|
655
|
+
// ──────────────────────────────────────────── Effective model info (PRD: what-will-this-run-as)
|
|
656
|
+
const agentsResolveModelInfo = z.object({
|
|
657
|
+
cwd: z.string().min(1).max(4096),
|
|
658
|
+
agentType: z.string().min(1).max(200),
|
|
659
|
+
}).strict();
|
|
660
|
+
|
|
661
|
+
// ──────────────────────────────────────────── Epic launch model (PRD: unify-epic-model-resolution)
|
|
662
|
+
// Terminal's (EpicTerminalPane.tsx) call into agentModelResolve.cjs's
|
|
663
|
+
// resolveEpicModel — the same launch-model authority chatRunner.cjs's Chat
|
|
664
|
+
// path calls in-process, reached here over IPC since the renderer has no fs.
|
|
665
|
+
const agentsResolveEpicModel = z.object({
|
|
666
|
+
cwd: z.string().min(1).max(4096),
|
|
667
|
+
claudeSessionId: z.string().min(1).max(200),
|
|
668
|
+
}).strict();
|
|
669
|
+
|
|
626
670
|
// ──────────────────────────────────────────── Project Pages (PRD 932)
|
|
627
671
|
// Same validation split as projectBriefCwd above: real path validation is
|
|
628
672
|
// config.cjs's validatePath at first fs access in projectPages.cjs.
|
|
@@ -1037,6 +1081,7 @@ module.exports = {
|
|
|
1037
1081
|
scheduleReadLog,
|
|
1038
1082
|
scheduleWritePrd,
|
|
1039
1083
|
schedulerCreatePrd,
|
|
1084
|
+
scheduleSetPrdDisposition,
|
|
1040
1085
|
scheduleArchivePrd,
|
|
1041
1086
|
scheduleRetagPrd,
|
|
1042
1087
|
adminListPrdsQuery,
|
|
@@ -1108,6 +1153,8 @@ module.exports = {
|
|
|
1108
1153
|
exchangesList,
|
|
1109
1154
|
agentsSavePersona,
|
|
1110
1155
|
agentsGetPersonaBody,
|
|
1156
|
+
agentsResolveModelInfo,
|
|
1157
|
+
agentsResolveEpicModel,
|
|
1111
1158
|
delegationReadinessCwd,
|
|
1112
1159
|
telemetrySetConfig,
|
|
1113
1160
|
},
|