claude-code-session-manager 0.66.0 → 0.67.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.
Files changed (38) hide show
  1. package/dist/assets/{AgentLibrary-Bzg89D5Y.js → AgentLibrary-CiqimwWl.js} +1 -1
  2. package/dist/assets/{History-CNH9vA0A.js → History-DbzjII2Z.js} +1 -1
  3. package/dist/assets/{Hooks-CyTksPza.js → Hooks-C0PTplI_.js} +2 -2
  4. package/dist/assets/{HostBilko-DXQVDNHn.js → HostBilko-vGc1FYLD.js} +1 -1
  5. package/dist/assets/{Library-9E2UOIsm.js → Library-4tU4rg2h.js} +1 -1
  6. package/dist/assets/{ListDetail-CQWU_Yn5.js → ListDetail-BGIvkCwZ.js} +1 -1
  7. package/dist/assets/{MarkdownEditor-DQgfpSef.js → MarkdownEditor-ChFdpCam.js} +1 -1
  8. package/dist/assets/{McpServers-r3qwDIj2.js → McpServers-DsRWWpU3.js} +2 -2
  9. package/dist/assets/{Memory-BaxOpj-3.js → Memory-DmxoxxxY.js} +1 -1
  10. package/dist/assets/{Panel-BhFD8Lqo.js → Panel-KC-rv3jS.js} +1 -1
  11. package/dist/assets/{Permissions-Cj-mODQQ.js → Permissions-DrDjCRFl.js} +2 -2
  12. package/dist/assets/{Plugins-DEL3Fqng.js → Plugins-KexSQwk0.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-CIAg6-JQ.js → ProvenanceBadge-Rg-jL94y.js} +1 -1
  14. package/dist/assets/SaveBar-BbEo8U2e.js +1 -0
  15. package/dist/assets/{Scheduler-YOuZKkES.js → Scheduler-C4Ti9TCc.js} +1 -1
  16. package/dist/assets/ScopeSwitcher-Di9BmYze.js +1 -0
  17. package/dist/assets/Settings-CxyhPuYQ.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-CoIwsol8.js → SkillReferenceGraph-0q26RHrn.js} +1 -1
  19. package/dist/assets/{Skills-CN8R6AWn.js → Skills-BXkVyCo5.js} +2 -2
  20. package/dist/assets/SystemPrompt-Bwe3NTbi.js +1 -0
  21. package/dist/assets/{TagLibrary-BKmz2W7B.js → TagLibrary-CnwEf6EI.js} +1 -1
  22. package/dist/assets/{TiptapBody-W7n5SwPM.js → TiptapBody-faCtLj9L.js} +1 -1
  23. package/dist/assets/{Toggle-QuxlVHGI.js → Toggle-Bw7G_-RR.js} +1 -1
  24. package/dist/assets/{index-TejhHSzN.js → index-B6dJ2CsU.js} +323 -323
  25. package/dist/assets/{index-14dBLqE_.css → index-CEnMgeQU.css} +1 -1
  26. package/dist/assets/{settingsSchema-DNqx6BKJ.js → settingsSchema-B5C9hZoS.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/package.json +1 -1
  29. package/plugins/session-manager-dev/skills/develop/SKILL.md +41 -11
  30. package/src/main/__tests__/develop-skill-failure-modes.test.cjs +70 -0
  31. package/src/main/__tests__/health-per-project-stall.test.cjs +82 -0
  32. package/src/main/__tests__/scheduler-stall-per-project.test.cjs +108 -0
  33. package/src/main/health.cjs +97 -2
  34. package/src/main/lib/schedulerConfig.cjs +7 -0
  35. package/src/main/scheduler.cjs +154 -35
  36. package/dist/assets/ScopeSwitcher-DZ_3gEus.js +0 -1
  37. package/dist/assets/Settings-B0x4oflz.js +0 -3
  38. package/dist/assets/SystemPrompt-DceChpAi.js +0 -1
@@ -75,7 +75,11 @@ const {
75
75
  USAGE_REFRESH_INTERVAL_MS,
76
76
  MAX_JOB_DURATION_MS,
77
77
  BROADCAST_COALESCE_MS,
78
+ QUARANTINE_ESCALATE_MS: QUARANTINE_ESCALATE_MS_DEFAULT,
78
79
  } = require('./lib/schedulerConfig.cjs');
80
+ const QUARANTINE_ESCALATE_MS = process.env.SM_QUARANTINE_ESCALATE_HOURS
81
+ ? Number(process.env.SM_QUARANTINE_ESCALATE_HOURS) * 60 * 60_000
82
+ : QUARANTINE_ESCALATE_MS_DEFAULT;
79
83
  const { pickForProject, pickNextBatch, DEFAULT_PROJECT_CWD } = require('./lib/schedulerBatch.cjs');
80
84
  const { runDefinitionOfDoneOnDrain } = require('./lib/dodDrainHook.cjs');
81
85
  const { writeRcaReport, extractRcaBlock } = require('./lib/rcaReport.cjs');
@@ -961,13 +965,24 @@ function appendHeartbeat(entry) {
961
965
  * computeStallSummary(state) → { stalled, total, running, pending, byProject }
962
966
  *
963
967
  * Pure, no IO. `state` is a merged queue-store read ({ jobs, invalidJobs,
964
- * paused }). "Stalled" = the queue holds work — valid rows OR rows
965
- * quarantined for an invalid status — but nothing is running or pending and
966
- * the scheduler isn't paused. The 2026-08-07 incident sat exactly in this
967
- * state for 4+ hours: 2 jobs, 0 running, 0 pending, and the only visible
968
- * symptom was a heartbeat `counts` object that had silently minted a
969
- * `queued` bucket instead of reporting anything actionable. `byProject`
970
- * breaks the stalled rows down by cwd for the log line / toast.
968
+ * paused }). The engine (reconcile/reaper/auto-fix/reverify) already
969
+ * operates machine-wide via queueStore's stateCwds() — this function is
970
+ * MONITORING, and monitoring must not collapse per-project reality into one
971
+ * boolean. `stalled` (top-level) is the pre-existing machine-wide roll-up:
972
+ * the queue holds work — valid rows OR rows quarantined for an invalid
973
+ * status — but nothing anywhere is running or pending and the scheduler
974
+ * isn't paused. The 2026-08-07 incident sat exactly in this state for 4+
975
+ * hours: 2 jobs, 0 running, 0 pending, and the only visible symptom was a
976
+ * heartbeat `counts` object that had silently minted a `queued` bucket
977
+ * instead of reporting anything actionable.
978
+ *
979
+ * `byProject[cwd].stalled` is the PER-PROJECT verdict added for the
980
+ * "burrow went dark while other projects were busy" gap: a project can hold
981
+ * jobs (including ones parked `quarantined`) with 0 running and 0 pending
982
+ * while the machine-wide `stalled` above reads false because a different
983
+ * project has running/pending work. Each project's own status counts
984
+ * (`byProject[cwd][status]`) already summed to a total before this — the
985
+ * fix is only the boolean, not the counting.
971
986
  */
972
987
  function computeStallSummary(state) {
973
988
  const jobs = Array.isArray(state?.jobs) ? state.jobs : [];
@@ -989,9 +1004,45 @@ function computeStallSummary(state) {
989
1004
  }
990
1005
  const total = jobs.length + invalidJobs.length;
991
1006
  const stalled = total > 0 && running === 0 && pending === 0 && !state?.paused;
1007
+ for (const key of Object.keys(byProject)) {
1008
+ const counts = byProject[key];
1009
+ const projRunning = counts.running || 0;
1010
+ const projPending = counts.pending || 0;
1011
+ const projTotal = Object.keys(counts)
1012
+ .filter((k) => k !== 'stalled')
1013
+ .reduce((sum, k) => sum + counts[k], 0);
1014
+ counts.stalled = projTotal > 0 && projRunning === 0 && projPending === 0 && !state?.paused;
1015
+ }
992
1016
  return { stalled, total, running, pending, byProject };
993
1017
  }
994
1018
 
1019
+ /**
1020
+ * findStaleQuarantinedJobs(jobs, now, thresholdMs) → [{ slug, cwd, ageMs }]
1021
+ *
1022
+ * Pure, no IO. A 'quarantined' row (no createdVia provenance) can otherwise
1023
+ * sit forever with nothing looking at it — quarantine only ever clears via a
1024
+ * human adopting or archiving it. This is the escalation half of that gate:
1025
+ * any quarantined row whose recorded quarantine timestamp (statusHistory's
1026
+ * `to === 'quarantined'` entry — stamped at creation, or backfilled from the
1027
+ * PRD file's mtime by reconcile() for rows quarantined before that stamp
1028
+ * existed) is older than `thresholdMs` is reported so the caller can
1029
+ * warn-log and surface it distinctly. A row with no recoverable timestamp is
1030
+ * skipped rather than guessed at.
1031
+ */
1032
+ function findStaleQuarantinedJobs(jobs, now, thresholdMs) {
1033
+ const stale = [];
1034
+ for (const j of jobs ?? []) {
1035
+ if (j.status !== 'quarantined') continue;
1036
+ const entry = (j.statusHistory || []).find((h) => h.to === 'quarantined');
1037
+ if (!entry) continue;
1038
+ const since = Date.parse(entry.at);
1039
+ if (Number.isNaN(since)) continue;
1040
+ const ageMs = now - since;
1041
+ if (ageMs >= thresholdMs) stale.push({ slug: j.slug, cwd: j.cwd ?? null, ageMs });
1042
+ }
1043
+ return stale;
1044
+ }
1045
+
995
1046
  // An empty queue and an unreadable queue are NOT the same thing, and
996
1047
  // conflating them is destructive: reconcile() treats every PRD .md with no
997
1048
  // matching jobs[] row as a brand-new goal and re-mints it as 'pending', so a
@@ -1356,6 +1407,21 @@ async function reconcile(state) {
1356
1407
  console.log(`[scheduler] reconcile: adopted quarantined PRD ${job.slug} — createdVia=${p.createdVia}`);
1357
1408
  appendAuditEvent('scheduler_prd_adopted', { slug: job.slug, cwd: p.cwd, createdVia: p.createdVia, source: 'reconcile' });
1358
1409
  }
1410
+ // Backfill a quarantine timestamp for rows quarantined before the
1411
+ // statusHistory stamp below existed (e.g. the burrow-project rows
1412
+ // quarantined under the PRD-authoring lockdown) — findStaleQuarantinedJobs
1413
+ // needs SOME timestamp to escalate an un-adopted row past its age
1414
+ // threshold, and the PRD file's own mtime is the best available proxy
1415
+ // for "when this file first showed up unstamped" for a row that has
1416
+ // never been touched since.
1417
+ if (updatedJob.status === 'quarantined' && !(updatedJob.statusHistory || []).some((h) => h.to === 'quarantined')) {
1418
+ try {
1419
+ const at = new Date(fs.statSync(p.path).mtimeMs).toISOString();
1420
+ const history = Array.isArray(updatedJob.statusHistory) ? [...updatedJob.statusHistory] : [];
1421
+ history.push({ from: null, to: 'quarantined', reason: 'backfilled from PRD file mtime', source: 'reconcile-backfill', at });
1422
+ updatedJob.statusHistory = history;
1423
+ } catch { /* best-effort only — a missing/unreadable file just skips the backfill */ }
1424
+ }
1359
1425
  next.push(updatedJob);
1360
1426
  }
1361
1427
  // Slugs on disk with no matching state.jobs row are normally brand-new
@@ -1590,6 +1656,18 @@ async function reconcile(state) {
1590
1656
  // to 'pending' on the very next pass, within one tick of being stamped.
1591
1657
  if (!p.createdVia && !isFixPlanSlug(slug)) {
1592
1658
  entry.status = 'quarantined';
1659
+ // Stamped at creation (not via transitionJob, since this is a
1660
+ // brand-new row minted directly at 'quarantined' rather than
1661
+ // transitioning through 'pending') so findStaleQuarantinedJobs has a
1662
+ // real quarantine timestamp to escalate against, instead of only the
1663
+ // reconcile-backfill fallback above.
1664
+ entry.statusHistory = [{
1665
+ from: null,
1666
+ to: 'quarantined',
1667
+ reason: 'missing createdVia provenance frontmatter',
1668
+ source: 'reconcile',
1669
+ at: new Date().toISOString(),
1670
+ }];
1593
1671
  console.warn(`[scheduler] reconcile: quarantining unstamped PRD ${slug} (${p.path}) — no createdVia provenance; adopt it from the Scheduler tab's Quarantined filter or via scheduler_update_prd to make it runnable`);
1594
1672
  appendAuditEvent('prd_quarantined', { slug, cwd: p.cwd, path: p.path, reason: 'missing createdVia provenance frontmatter' });
1595
1673
  }
@@ -1692,12 +1770,15 @@ let pollLoopTimer = null;
1692
1770
  let rescheduleInterval = null;
1693
1771
  let heartbeatInterval = null;
1694
1772
  // Stall-detector state (computeStallSummary), read/written only inside the
1695
- // heartbeat interval below. stallSince: wall-clock ms the stalled condition
1696
- // was first observed, null when clear. stallToasted: rate-limits the
1697
- // error-log + toast to once per stall episode (cleared the moment the queue
1698
- // stops being stalled) rather than every 60s heartbeat tick.
1699
- let stallSince = null;
1700
- let stallToasted = false;
1773
+ // heartbeat interval below. Keyed per-project cwd (never a single value) —
1774
+ // a single module-level flag would let one busy project's activity clear or
1775
+ // suppress another stalled project's alert. stallSince.get(cwd): wall-clock
1776
+ // ms that project's stalled condition was first observed, absent when clear.
1777
+ // stallToasted.get(cwd): rate-limits that project's error-log + toast to
1778
+ // once per stall episode (cleared the moment that project stops being
1779
+ // stalled) rather than every 60s heartbeat tick.
1780
+ let stallSince = new Map();
1781
+ let stallToasted = new Map();
1701
1782
  // (The 5-minute feedback sweep that used to piggyback on this heartbeat is
1702
1783
  // gone: it scanned each active project's session-manager-operations/feedback/
1703
1784
  // and auto-queued a /process-feedback PRD. Both the folder and that skill are
@@ -4924,6 +5005,7 @@ async function init() {
4924
5005
  if (rescheduleInterval) clearInterval(rescheduleInterval);
4925
5006
  rescheduleInterval = setInterval(() => {
4926
5007
  rescheduleTimer().catch(() => {});
5008
+ const s = readQueueSync();
4927
5009
  // Periodic self-heal: re-run the verifier over stale needs_review jobs so a
4928
5010
  // job whose work actually landed (committed in-window, no FAIL sentinel)
4929
5011
  // auto-clears WITHOUT waiting for the next app restart. Cheap-guarded — the
@@ -4933,10 +5015,32 @@ async function init() {
4933
5015
  // MAX_CONCURRENT_INVESTIGATIONS (spawnInvestigation queues/early-returns
4934
5016
  // past it), so this interval firing cannot fan out investigations.
4935
5017
  if (process.env.SM_REVERIFY_PERIODIC_DISABLE !== '1') {
4936
- const s = readQueueSync();
4937
5018
  if (s.jobs.some((j) => j.status === 'needs_review')) {
4938
5019
  reverifyNeedsReview().catch(() => {});
4939
5020
  }
5021
+ // A quarantined row only ever promotes to 'pending' through
5022
+ // reconcile()'s adopt path (see reconcile()'s "Adopt path" comment) —
5023
+ // it re-checks the PRD file's createdVia stamp every pass. broadcast()
5024
+ // already runs reconcile+writeQueue on every normal poll tick, but an
5025
+ // idle queue (nothing pending/running to fire) can back off that
5026
+ // cadence for a long time; this guarantees an adopted-but-still-
5027
+ // quarantined row is re-checked within 10 minutes regardless.
5028
+ if (s.jobs.some((j) => j.status === 'quarantined')) {
5029
+ broadcast().catch(() => {});
5030
+ }
5031
+ }
5032
+ // Age-based escalation (independent of the self-heal kill-switch above —
5033
+ // this is a monitoring signal, not an auto-fix action): a quarantined
5034
+ // row nobody has adopted or archived past QUARANTINE_ESCALATE_MS is
5035
+ // warn-logged by project + slug + age so it cannot sit stranded and
5036
+ // silent (the four burrow-project rows this PRD was written against).
5037
+ for (const stale of findStaleQuarantinedJobs(s.jobs, Date.now(), QUARANTINE_ESCALATE_MS)) {
5038
+ console.warn(
5039
+ `[scheduler] QUARANTINED PRD STALE: project=${stale.cwd ?? '(unknown)'} slug=${stale.slug} `
5040
+ + `age=${Math.round(stale.ageMs / 3_600_000)}h (>= ${Math.round(QUARANTINE_ESCALATE_MS / 3_600_000)}h threshold) — `
5041
+ + `adopt it from the Scheduler tab's Quarantined filter, or archive it; nothing else will clear this`,
5042
+ );
5043
+ appendAuditEvent('prd_quarantine_stale', { slug: stale.slug, cwd: stale.cwd, ageMs: stale.ageMs });
4940
5044
  }
4941
5045
  }, 10 * 60_000);
4942
5046
 
@@ -4981,27 +5085,42 @@ async function init() {
4981
5085
  }
4982
5086
 
4983
5087
  const stall = computeStallSummary(s);
4984
- if (stall.stalled) {
4985
- if (stallSince === null) stallSince = Date.now();
4986
- if (!stallToasted && Date.now() - stallSince >= POLL_INTERVAL_MS) {
4987
- stallToasted = true;
4988
- console.error(
4989
- `[scheduler] STALL DETECTED: ${stall.total} job(s) queued, 0 running, 0 pending, not paused, `
4990
- + `for >= ${Math.round(POLL_INTERVAL_MS / 1000)}s`,
4991
- stall.byProject,
4992
- );
4993
- appendAuditEvent('scheduler_stall_detected', { total: stall.total, byProject: stall.byProject });
4994
- if (mainWindow && !mainWindow.isDestroyed()) {
4995
- sendIfAlive(mainWindow, 'schedule:stall', {
4996
- message: `Scheduler stall: ${stall.total} job(s) queued but none running or pending. Check the Scheduler tab.`,
4997
- total: stall.total,
4998
- byProject: stall.byProject,
4999
- });
5000
- }
5088
+ // Per-project alerting (see computeStallSummary's header): a project
5089
+ // stalled while others are busy must still fire, and one project
5090
+ // recovering must not clear or suppress another's still-open episode —
5091
+ // that is exactly what a single module-level stallSince/stallToasted
5092
+ // flag masked before (the burrow-vs-others incident this PRD fixes).
5093
+ const now = Date.now();
5094
+ const stalledCwds = Object.keys(stall.byProject).filter((cwd) => stall.byProject[cwd].stalled);
5095
+ for (const cwd of [...stallSince.keys()]) {
5096
+ if (!stalledCwds.includes(cwd)) {
5097
+ stallSince.delete(cwd);
5098
+ stallToasted.delete(cwd);
5099
+ }
5100
+ }
5101
+ const toAlert = [];
5102
+ for (const cwd of stalledCwds) {
5103
+ if (!stallSince.has(cwd)) stallSince.set(cwd, now);
5104
+ if (!stallToasted.get(cwd) && now - stallSince.get(cwd) >= POLL_INTERVAL_MS) {
5105
+ stallToasted.set(cwd, true);
5106
+ toAlert.push(cwd);
5107
+ }
5108
+ }
5109
+ if (toAlert.length > 0) {
5110
+ console.error(
5111
+ `[scheduler] STALL DETECTED in project(s): ${toAlert.join(', ')} — 0 running, 0 pending, not paused, `
5112
+ + `for >= ${Math.round(POLL_INTERVAL_MS / 1000)}s`,
5113
+ stall.byProject,
5114
+ );
5115
+ appendAuditEvent('scheduler_stall_detected', { projects: toAlert, total: stall.total, byProject: stall.byProject });
5116
+ if (mainWindow && !mainWindow.isDestroyed()) {
5117
+ sendIfAlive(mainWindow, 'schedule:stall', {
5118
+ message: `Scheduler stall in ${toAlert.length} project(s): ${toAlert.join(', ')}. Check the Scheduler tab.`,
5119
+ projects: toAlert,
5120
+ total: stall.total,
5121
+ byProject: stall.byProject,
5122
+ });
5001
5123
  }
5002
- } else {
5003
- stallSince = null;
5004
- stallToasted = false;
5005
5124
  }
5006
5125
 
5007
5126
  appendHeartbeat({
@@ -5507,4 +5626,4 @@ function registerAdminRoutes(adminHttp, remoteObj = remote) {
5507
5626
  });
5508
5627
  }
5509
5628
 
5510
- module.exports = { registerScheduleHandlers, attachWindow, init, ROOT, PRDS_DIR, healRefusalReason, writeQueue, reconcile, reconcileSourcePromptId, allocateParallelGroup, selectHistoryJobs, parsePorcelain, FINISH_PROTOCOL, remote, pickNextBatch, pickForProject, reapDeadRunningJobs, pollRecoveryClearSource, memoryLimitedBatchSize, availableForJobs, reverifyNeedsReview, isRescanCandidate, isPromotableOriginal, selectAutoFixTargets, isEligibleForImmediateAutoFix, resolveRunId, isUnresolvableNeedsReview, healTargetForFix, buildInvestigationPrompt, isGitRepoSync, committedInWindow, computeCommittedDuringRun, classifySigtermWithCommit, isFixPlanSlug, isFixPlanBeyondDepthCap, MAX_INVESTIGATION_DEPTH, forceTickOutcome, applyPauseCleared, detectNetworkErrorInLog, detectRateLimitInLog, classifyFailureOutcome, commitGuardVerdict, TRANSIENT_RETRY_CAP, buildScheduleStatePayload, partitionBootOrphans, applyOrphanOutcome, BOOT_ORPHAN_KILL_GRACE_MS, registerAdminRoutes, notifyOriginatingTab, notifyNeedsReview, isNotifiableTerminalStatus, extractResultTextFromLog, candidatePrdsDirs, candidateArchivedPrdsDirs, resolveArchivedPrdStatus, prdDirForCwd, prdPathForJob, archivedPrdPathForJob, archivedTwinExists, findPrdDir, resolveVerifyPrdPath, resolveNotifyPrd, runPrdMigration, consolidateAllFlatPrds, shouldSkipInvestigationForCleanRun, archiveCompletedPrd, retireCompletedSlugs, SCHEDULER_BOOTED_AT, SCHEDULER_CODE_SHA, resetJobFields, executeJob, prdArchivedSkipResult, spawnJob, listPrdsInternal, computeStallSummary };
5629
+ module.exports = { registerScheduleHandlers, attachWindow, init, ROOT, PRDS_DIR, healRefusalReason, writeQueue, reconcile, reconcileSourcePromptId, allocateParallelGroup, selectHistoryJobs, parsePorcelain, FINISH_PROTOCOL, remote, pickNextBatch, pickForProject, reapDeadRunningJobs, pollRecoveryClearSource, memoryLimitedBatchSize, availableForJobs, reverifyNeedsReview, isRescanCandidate, isPromotableOriginal, selectAutoFixTargets, isEligibleForImmediateAutoFix, resolveRunId, isUnresolvableNeedsReview, healTargetForFix, buildInvestigationPrompt, isGitRepoSync, committedInWindow, computeCommittedDuringRun, classifySigtermWithCommit, isFixPlanSlug, isFixPlanBeyondDepthCap, MAX_INVESTIGATION_DEPTH, forceTickOutcome, applyPauseCleared, detectNetworkErrorInLog, detectRateLimitInLog, classifyFailureOutcome, commitGuardVerdict, TRANSIENT_RETRY_CAP, buildScheduleStatePayload, partitionBootOrphans, applyOrphanOutcome, BOOT_ORPHAN_KILL_GRACE_MS, registerAdminRoutes, notifyOriginatingTab, notifyNeedsReview, isNotifiableTerminalStatus, extractResultTextFromLog, candidatePrdsDirs, candidateArchivedPrdsDirs, resolveArchivedPrdStatus, prdDirForCwd, prdPathForJob, archivedPrdPathForJob, archivedTwinExists, findPrdDir, resolveVerifyPrdPath, resolveNotifyPrd, runPrdMigration, consolidateAllFlatPrds, shouldSkipInvestigationForCleanRun, archiveCompletedPrd, retireCompletedSlugs, SCHEDULER_BOOTED_AT, SCHEDULER_CODE_SHA, resetJobFields, executeJob, prdArchivedSkipResult, spawnJob, listPrdsInternal, computeStallSummary, findStaleQuarantinedJobs, QUARANTINE_ESCALATE_MS };
@@ -1 +0,0 @@
1
- import{K as e,G as o,S as x}from"./index-TejhHSzN.js";function f({dirty:i,busy:a,parseError:t,lastSavedAt:c,onSave:s,onRevert:l,leading:n}){const d=i&&!a&&!t;return e.jsxs("div",{className:"px-3 py-1.5 flex items-center gap-2 text-xs",children:[e.jsx("div",{className:"flex-1 min-w-0 truncate text-fg-faint",children:n}),t&&e.jsx("span",{className:"text-red-400 truncate max-w-xs",title:t,children:t}),!i&&!t&&c&&e.jsx("span",{className:"text-fg-faint",children:o(c)}),i&&!t&&e.jsx("span",{className:"text-accent",children:"unsaved"}),e.jsx("button",{onClick:l,disabled:!i||a,className:"px-2 py-0.5 border border-line rounded text-fg-dim hover:text-fg hover:bg-bg-hi disabled:opacity-40 disabled:cursor-not-allowed",children:"Revert"}),e.jsx("button",{onClick:s,disabled:!d,className:`px-2.5 py-0.5 rounded border ${d?"border-accent bg-accent/15 text-accent hover:bg-accent/25":"border-line text-fg-faint opacity-50 cursor-not-allowed"}`,children:a?"Saving…":"Save"})]})}function b({scopes:i,active:a,onChange:t,annotate:c}){return e.jsx("div",{className:"inline-flex rounded border border-line overflow-hidden",children:i.map(s=>{const l=x[s],n=c==null?void 0:c(s),d=s===a;return e.jsxs("button",{title:l.hint,onClick:()=>t(s),className:`px-2.5 py-1 text-xs flex items-center gap-1.5 transition-colors ${d?"bg-bg-hi text-fg":"bg-bg-elev text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[e.jsx("span",{children:l.label}),(n==null?void 0:n.dirty)&&e.jsx("span",{className:"w-1 h-1 rounded-full bg-accent",title:"unsaved edits"}),n&&n.exists===!1&&!n.dirty&&e.jsx("span",{className:"w-1 h-1 rounded-full bg-fg-faint",title:"not yet created"})]},s)})})}export{f as S,b as a};
@@ -1,3 +0,0 @@
1
- import{Y as x,K as e,S as k,a as W,d as M,af as q,R as Y,aa as Z,ai as $,ac as Q,a8 as R,J as X,V as ee,n as F}from"./index-TejhHSzN.js";import{P as te}from"./Panel-BhFD8Lqo.js";import{S as se,a as ae}from"./ScopeSwitcher-DZ_3gEus.js";import{u as re,m as ne,p as le,a as U,E as ie,s as oe}from"./settingsSchema-DNqx6BKJ.js";import{T as H}from"./Toggle-QuxlVHGI.js";import"./monaco-editor-BW5C4Iv1.js";const ce=[{id:"essentials",title:"Essentials",summary:"The knobs you reach for first.",keys:["model","language","outputStyle","permissions"]},{id:"git",title:"Git & Commits",summary:"How Claude writes commits and pull requests on your behalf.",keys:["attribution","includeGitInstructions","includeCoAuthoredBy"]},{id:"memory",title:"Memory & Plans",summary:"Context Claude keeps between sessions and where it files plans.",keys:["autoMemoryEnabled","plansDirectory","claudeMdExcludes","respectGitignore"]},{id:"model",title:"Model & Reasoning",summary:"Model allow/override lists, reasoning depth, and fast-mode toggles — machine-wide, with no per-Epic override yet. An Epic's Agent persona model (Agent Library) still wins over Essentials' plain model default.",advanced:!0,keys:["availableModels","modelOverrides","effortLevel","fastMode","fastModePerSessionOptIn","alwaysThinkingEnabled"]},{id:"interface",title:"Interface",summary:"Visual polish — spinners, progress bars, motion.",keys:["spinnerTipsEnabled","spinnerTipsOverride","spinnerVerbs","terminalProgressBarEnabled","showTurnDuration","prefersReducedMotion","companyAnnouncements","statusLine","teammateMode"]},{id:"updates",title:"Updates & Cleanup",summary:"Release channel and how long transcripts stick around.",keys:["autoUpdatesChannel","cleanupPeriodDays"]},{id:"env",title:"Environment & Auth",summary:"Environment variables and auth-helper scripts.",keys:["env","apiKeyHelper","awsCredentialExport","awsAuthRefresh"]},{id:"hooks",title:"Hooks",summary:"Scripts Claude runs before/after tool use.",keys:["hooks","disableAllHooks","allowedHttpHookUrls","httpHookAllowedEnvVars"]},{id:"mcp",title:"MCP Servers",summary:"External tool providers Claude can talk to.",keys:["enableAllProjectMcpServers","enabledMcpjsonServers","disabledMcpjsonServers"]},{id:"plugins",title:"Plugins",summary:"Installed plugins, marketplaces, and per-plugin configuration.",keys:["enabledPlugins","extraKnownMarketplaces","skippedPlugins","skippedMarketplaces","pluginConfigs"]},{id:"filesystem",title:"File Picker & Sandbox",summary:"How Claude browses files and the sandbox it runs in.",keys:["fileSuggestion","sandbox","worktree"]},{id:"login",title:"Login",summary:"Which login method to force on startup.",keys:["forceLoginMethod","forceLoginOrgUUID"]},{id:"feedback",title:"Feedback",summary:"Session-quality surveys.",keys:["feedbackSurveyRate"]},{id:"advanced",title:"Advanced / Enterprise",summary:"Managed-settings-only keys and enterprise allow/denylists.",advanced:!0,keys:["allowedMcpServers","deniedMcpServers","allowManagedHooksOnly","allowManagedPermissionRulesOnly","allowManagedMcpServersOnly","strictKnownMarketplaces","blockedMarketplaces","pluginTrustMessage","otelHeadersHelper","skipWebFetchPreflight"]}],de={mcp:"MCP",url:"URL",urls:"URLs",http:"HTTP",ui:"UI",id:"ID",uuid:"UUID",api:"API",aws:"AWS",otel:"OTel",json:"JSON"};function G(a){return a.replace(/^\$/,"").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").toLowerCase().split(/\s+/).filter(Boolean).map((l,r)=>{const n=de[l];return n||(r===0?l.charAt(0).toUpperCase()+l.slice(1):l)}).join(" ")}function J(a){const s=new Set,t=[];for(const r of ce){const n=r.keys.filter(i=>a.has(i));n.forEach(i=>s.add(i)),n.length!==0&&t.push({id:r.id,title:r.title,summary:r.summary,advanced:!!r.advanced,keys:n})}const l=Array.from(a).filter(r=>!s.has(r)&&r!=="$schema").sort();return l.length>0&&t.push({id:"other",title:"Other",summary:"Keys not yet grouped.",advanced:!1,keys:l}),t}function ue(a,s){return J(a).map(t=>({id:t.id,title:t.title,advanced:t.advanced,total:t.keys.length,setCount:t.keys.filter(l=>s.has(l)).length}))}const xe={};function B(a,s){if(s)return{text:s,authored:!1};const t=xe[a];return t?{text:t,authored:!0}:null}const pe={essentials:"star",git:"link",memory:"memory",model:"sparkle",interface:"eye",updates:"reload",env:"keys",hooks:"hooks",mcp:"mcp",plugins:"plugins",filesystem:"folder",login:"lock",feedback:"send",advanced:"shield",other:"dot"},me=["user","project","local","default"],fe={user:"user",project:"project",local:"local",default:"default"};function ge({node:a,targetScope:s,onOverride:t,schema:l}){const[r,n]=x.useState(""),[i,p]=x.useState(!1),[m,j]=x.useState(!0),u=a.kind==="object"?a:null,S=u?Object.keys(u.children):[],h=l.rootKeys(),N=new Set([...S,...h]),f=x.useMemo(()=>J(N),[Array.from(N).sort().join(",")]),b=x.useMemo(()=>ue(N,new Set(S)),[Array.from(N).sort().join(","),S.join(",")]),[C,E]=x.useState(null),c=x.useRef(null),w=o=>{const g=f.find(v=>v.id===o);g!=null&&g.advanced&&!i&&p(!0),E(o)};x.useEffect(()=>{if(!C)return;E(null);const o=c.current,g=document.getElementById(`settings-group-${C}`);if(!o||!g)return;const v=g.getBoundingClientRect().top-o.getBoundingClientRect().top;o.scrollBy({top:v,behavior:"smooth"})},[C]);const y=x.useMemo(()=>f.filter(o=>i||!o.advanced).map(o=>({...o,keys:o.keys.filter(g=>{const v=(u==null?void 0:u.children[g])!==void 0;if(!m&&!v)return!1;if(!r.trim())return!0;const T=l.at([g]);return[g,G(g),(T==null?void 0:T.description)??""].join(" ").toLowerCase().includes(r.toLowerCase())})})).filter(o=>o.keys.length>0),[f,r,i,m,u,l]);return e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"shrink-0 border-b border-line bg-bg-elev px-3 py-1.5 flex items-center gap-3 text-xs",children:[e.jsxs("span",{className:"text-fg-faint",children:["writing overrides to"," ",e.jsx("span",{className:"text-fg-dim font-medium",children:k[s].label})]}),e.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:m,onChange:o=>j(o.target.checked),className:"accent-accent"}),"show not-yet-configured"]}),e.jsxs("label",{className:"flex items-center gap-1 text-fg-faint cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:i,onChange:o=>p(o.target.checked),className:"accent-accent"}),"show advanced"]}),e.jsx("div",{className:"flex-1"}),e.jsx("input",{value:r,onChange:o=>n(o.target.value),placeholder:"search settings…",className:"bg-bg border border-line rounded px-2 py-1 text-xs text-fg w-64"})]}),e.jsxs("div",{className:"flex-1 flex overflow-hidden",children:[e.jsx(he,{groups:b,onJump:w}),e.jsxs("div",{ref:c,className:"flex-1 overflow-auto py-3",children:[y.map(o=>e.jsx(be,{id:o.id,title:o.title,summary:o.summary,advanced:o.advanced,children:o.keys.map(g=>{const v=u==null?void 0:u.children[g],T=l.at([g]);return e.jsx(ve,{keyName:g,node:v,info:T,targetScope:s,onOverride:(d,A)=>t([g],d,A)},g)})},o.id)),y.length===0&&e.jsxs("div",{className:"px-6 py-12 text-center text-fg-faint text-sm",children:['no settings match "',r,'"']})]})]})]})}function he({groups:a,onJump:s}){return e.jsx("nav",{className:"shrink-0 w-48 border-r border-line bg-bg-elev/30 overflow-y-auto py-3",children:a.map(t=>e.jsxs("button",{onClick:()=>s(t.id),className:"w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-bg-hi transition-colors",title:`jump to ${t.title}`,children:[e.jsx(W,{name:pe[t.id]??"dot",size:15,className:"text-fg-faint shrink-0"}),e.jsx("span",{className:"flex-1 min-w-0 truncate text-xs text-fg-dim",children:t.title}),e.jsxs("span",{className:"text-[10px] text-fg-faint font-mono shrink-0",children:[t.setCount,"/",t.total]})]},t.id))})}function be({id:a,title:s,summary:t,advanced:l,children:r}){const[n,i]=x.useState(!0);return e.jsxs("section",{id:`settings-group-${a}`,className:"mx-4 mb-4 rounded-lg border border-line shadow-sm bg-bg-elev/50 overflow-hidden",children:[e.jsxs("header",{className:"px-4 py-3 bg-bg-elev cursor-pointer hover:bg-bg-hi flex items-center gap-3 border-b border-line",onClick:()=>i(!n),children:[e.jsx("span",{className:"text-fg-faint w-3",children:n?"▾":"▸"}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-fg text-base font-semibold",children:s}),l&&e.jsx("span",{className:"text-[9px] px-1.5 py-0 rounded border border-yellow-900/40 bg-yellow-950/30 text-yellow-500/80 uppercase tracking-wide",children:"advanced"})]}),e.jsx("p",{className:"text-fg-dim text-sm mt-0.5",children:t})]})]}),n&&e.jsx("div",{className:"divide-y divide-line/60",children:r})]})}function ve({keyName:a,node:s,info:t,targetScope:l,onOverride:r}){const[n,i]=x.useState(!1),[p,m]=x.useState(!1),j=G(a),u=s!==void 0,h=(s==null?void 0:s.kind)==="leaf"?s:null,N=(s==null?void 0:s.kind)==="object"||(s==null?void 0:s.kind)==="array",f=t==null?void 0:t.default,b=h&&f!==void 0&&V(h.value,f),C=Ee({isSet:u,leafNode:h,defaultVal:f,isDefault:!!b,node:s}),E=ye(h,f),c=E.length>=2,w=!!h&&!b,y=B(a,t==null?void 0:t.description);return e.jsx("div",{className:"px-4 py-3 hover:bg-bg-elev/20",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("button",{onClick:()=>i(!n),className:"text-fg-faint hover:text-fg w-3 mt-0.5",title:n?"collapse":"expand",children:n?"▾":"▸"}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-baseline gap-2 flex-wrap",children:[e.jsx("h3",{className:"text-fg text-sm",children:j}),e.jsx(Te,{kind:C.kind,label:C.label}),c&&e.jsxs("button",{onClick:o=>{o.stopPropagation(),n||i(!0),m(g=>!g)},className:"text-[9px] px-1.5 py-0 rounded border border-blue-900/40 bg-blue-950/30 text-blue-300/90 uppercase tracking-wide hover:bg-blue-900/40",title:"this key is defined in multiple scopes — click to expand",children:["drift · ",E.map(o=>fe[o]).join(" · ")]}),w&&h&&e.jsx("button",{onClick:o=>{o.stopPropagation(),r(void 0,h.winner)},className:"text-[9px] px-1.5 py-0 rounded border border-line bg-bg-elev text-fg-faint uppercase tracking-wide hover:text-fg hover:bg-bg-hi",title:`reset · delete from ${k[h.winner].label}`,children:"↺ reset"}),(t==null?void 0:t.deprecated)&&e.jsx("span",{className:"text-[9px] px-1 py-0 rounded border border-yellow-900/40 bg-yellow-950/30 text-yellow-500/80 uppercase tracking-wide",children:"deprecated"}),(t==null?void 0:t.required)&&!u&&e.jsx("span",{className:"text-[9px] px-1 py-0 rounded border border-red-900/40 bg-red-950/30 text-red-400/80 uppercase tracking-wide",children:"required"})]}),y&&e.jsx("p",{className:`text-fg-dim text-xs mt-0.5 leading-relaxed ${y.authored?"inline-block border-b border-dotted border-fg-faint/70 cursor-help":""}`,title:y.authored?"In-app-authored description — not from the official Claude Code schema":void 0,children:Oe(y.text)}),n&&p&&h&&e.jsx(je,{leaf:h,defaultVal:f,onReset:o=>r(void 0,o)}),n&&e.jsx(Ne,{keyName:a,node:s,info:t,targetScope:l,onOverride:o=>r(o)})]}),e.jsx("div",{className:"shrink-0",children:!n&&e.jsx(Ce,{node:s,info:t,onSet:o=>{r(o)},disabled:N&&u})})]})})}function ye(a,s){if(!a)return[];const t=new Set;t.add(a.winner);for(const l of a.shadowed)t.add(l.scope);return s!==void 0&&t.add("default"),me.filter(l=>t.has(l))}function je({leaf:a,defaultVal:s,onReset:t}){const l={};l[a.winner]={value:a.value,winner:!0};for(const r of a.shadowed)l[r.scope]={value:r.value,winner:!1};return e.jsxs("div",{className:"mt-2 border border-line rounded bg-bg-elev/40 text-xs",children:[e.jsx("div",{className:"px-2 py-1 text-fg-faint border-b border-line/60",children:"Values across all scopes (winner highlighted · reset removes that scope's value):"}),e.jsxs("div",{className:"divide-y divide-line/60",children:[["user","project","local"].map(r=>{const n=l[r],i=n!==void 0;return e.jsxs("div",{className:"grid grid-cols-[5rem_1fr_auto] gap-2 px-2 py-1 items-center",children:[e.jsx("span",{className:"text-fg-faint",children:k[r].label}),e.jsx("span",{className:`font-mono truncate ${n!=null&&n.winner?"text-accent":"text-fg-dim"}`,children:i?P(n.value):e.jsx("span",{className:"text-fg-faint",children:"—"})}),i?e.jsx("button",{onClick:()=>t(r),className:"text-[9px] px-1.5 py-0 rounded border border-line text-fg-faint uppercase tracking-wide hover:text-fg hover:bg-bg-hi",title:`delete this key from ${k[r].label}`,children:"↺"}):e.jsx("span",{})]},r)}),e.jsxs("div",{className:"grid grid-cols-[5rem_1fr_auto] gap-2 px-2 py-1 items-center",children:[e.jsx("span",{className:"text-fg-faint",children:"Default"}),e.jsx("span",{className:"font-mono text-fg-dim truncate",children:s!==void 0?P(s):e.jsx("span",{className:"text-fg-faint",children:"—"})}),e.jsx("span",{})]})]})]})}function Ne({keyName:a,node:s,info:t,targetScope:l,onOverride:r}){const i=(s==null?void 0:s.kind)==="leaf"?s:null,p=B(a,t==null?void 0:t.description);return e.jsxs("div",{className:"mt-3 space-y-2 text-xs",children:[p&&e.jsx("p",{className:`text-fg-dim leading-relaxed whitespace-pre-wrap ${p.authored?"inline-block border-b border-dotted border-fg-faint/70 cursor-help":""}`,title:p.authored?"In-app-authored description — not from the official Claude Code schema":void 0,children:p.text}),e.jsxs("dl",{className:"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-fg-faint",children:[(t==null?void 0:t.type)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Type"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:Array.isArray(t.type)?t.type.join(" | "):t.type})]}),(t==null?void 0:t.default)!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Default"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:P(t.default)})]}),(t==null?void 0:t.enum)&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Options"}),e.jsx("dd",{className:"text-fg-dim font-mono",children:t.enum.map(m=>String(m)).join(" | ")})]}),i&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Current"}),e.jsxs("dd",{className:"font-mono",children:[e.jsx("span",{className:"text-fg-dim",children:P(i.value)}),e.jsxs("span",{className:"ml-2 text-fg-faint",children:["from ",k[i.winner].label]})]})]}),i&&i.shadowed.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Shadowed"}),e.jsx("dd",{className:"space-y-0.5",children:i.shadowed.map((m,j)=>e.jsxs("div",{className:"font-mono text-fg-faint line-through",children:[P(m.value)," —"," ",e.jsx("span",{className:"no-underline",children:k[m.scope].label})]},j))})]}),(s==null?void 0:s.kind)==="array"&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{children:"Accumulated"}),e.jsxs("dd",{className:"text-fg-dim",children:[s.items.length," items across all scopes"]})]})]}),e.jsx("div",{className:"pt-2 flex items-center gap-2 flex-wrap border-t border-line/60",children:e.jsx(we,{keyName:a,node:s,info:t,onChange:r,targetScope:l})})]})}function we({node:a,info:s,onChange:t,targetScope:l}){const n=(a==null?void 0:a.kind)==="leaf"?a.value:s==null?void 0:s.default,i=K(s==null?void 0:s.type);if(i==="boolean"){const p=n===!0;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-fg-faint",children:"Set to:"}),e.jsx("div",{className:"inline-flex rounded border border-line overflow-hidden",children:[{v:!0,label:"on"},{v:!1,label:"off"}].map(({v:m,label:j})=>e.jsx("button",{onClick:()=>t(m),className:`px-3 py-0.5 text-xs transition-colors ${p===m?"bg-accent text-bg":"bg-bg-elev text-fg-dim hover:bg-bg-hi hover:text-fg"}`,children:j},j))}),e.jsxs("span",{className:"text-fg-faint",children:["→ ",k[l].label]})]})}return s!=null&&s.enum?e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("span",{className:"text-fg-faint",children:"Choose:"}),s.enum.map(p=>{const m=V(n,p);return e.jsx("button",{onClick:()=>t(p),className:`px-2 py-0.5 text-xs rounded border ${m?"bg-accent text-bg border-accent":"bg-bg-elev text-fg-dim border-line hover:text-fg hover:bg-bg-hi"}`,children:String(p)},String(p))}),e.jsxs("span",{className:"text-fg-faint",children:["→ ",k[l].label]})]}):i==="integer"||i==="number"?e.jsx(Se,{value:typeof n=="number"?n:void 0,integer:i==="integer",onCommit:t,target:k[l].label}):i==="string"?e.jsx(ke,{value:typeof n=="string"?n:"",onCommit:t,target:k[l].label}):e.jsxs("div",{className:"text-fg-faint",children:["Complex value (",i??"object/array",") — use the"," ",e.jsx("span",{className:"text-fg-dim",children:"Raw"})," tab to edit."]})}function Se({value:a,integer:s,onCommit:t,target:l}){const[r,n]=x.useState(a!==void 0?String(a):""),i=()=>{const p=s?parseInt(r,10):parseFloat(r);Number.isNaN(p)||t(p)};return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-fg-faint",children:"Set to:"}),e.jsx("input",{type:"number",value:r,onChange:p=>n(p.target.value),onBlur:i,onKeyDown:p=>{p.key==="Enter"&&p.target.blur()},className:"w-24 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg"}),e.jsxs("button",{onClick:i,className:"px-2 py-0.5 text-xs border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg",children:["save → ",l]})]})}function ke({value:a,onCommit:s,target:t}){const[l,r]=x.useState(a);return e.jsxs("div",{className:"flex items-center gap-2 flex-1 min-w-0",children:[e.jsx("span",{className:"text-fg-faint shrink-0",children:"Set to:"}),e.jsx("input",{type:"text",value:l,onChange:n=>r(n.target.value),onKeyDown:n=>{n.key==="Enter"&&s(l)},className:"flex-1 min-w-0 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg"}),e.jsxs("button",{onClick:()=>s(l),className:"shrink-0 px-2 py-0.5 text-xs border border-accent/50 rounded text-accent hover:bg-accent hover:text-bg",children:["save → ",t]})]})}function Ce({node:a,info:s,onSet:t,disabled:l}){const r=(a==null?void 0:a.kind)==="leaf",n=K(s==null?void 0:s.type);if(l)return null;if(n==="boolean"){const i=r&&a.value===!0;return e.jsx("button",{onClick:()=>t(!i),className:`px-2.5 py-0.5 text-xs rounded border transition-colors ${i?"bg-accent/15 text-accent border-accent/40 hover:bg-accent hover:text-bg":"bg-bg-elev text-fg-dim border-line hover:text-fg hover:bg-bg-hi"}`,title:"toggle",children:i?"on":"off"})}return null}function Ee({isSet:a,leafNode:s,defaultVal:t,isDefault:l,node:r}){return a?(r==null?void 0:r.kind)==="array"?{kind:"accumulated",label:`${r.items.length} items`}:(r==null?void 0:r.kind)==="object"?{kind:"set",label:"configured"}:s?l?{kind:"default",label:`= default · ${k[s.winner].label}`}:s.shadowed.length>0?{kind:"override",label:`overriding ${s.shadowed.length} scope(s)`}:{kind:"set",label:`set in ${k[s.winner].label}`}:{kind:"set",label:"configured"}:t!==void 0?{kind:"default",label:`using default: ${P(t)}`}:{kind:"unset",label:"not configured"}}function Te({kind:a,label:s}){const t={set:"bg-accent/15 text-accent border-accent/30",default:"bg-bg-hi text-fg-dim border-line",unset:"bg-bg-elev text-fg-faint border-line",override:"bg-purple-950/30 text-purple-400/80 border-purple-900/40",accumulated:"bg-blue-950/30 text-blue-400/80 border-blue-900/40"}[a];return e.jsx("span",{className:`text-[9px] px-1.5 py-0 rounded border uppercase tracking-wide ${t}`,children:s})}function K(a){if(a)return Array.isArray(a)?a.find(t=>t!=="null")??a[0]:a}function V(a,s){return a===s?!0:typeof a!=typeof s?!1:a&&s&&typeof a=="object"?JSON.stringify(a)===JSON.stringify(s):!1}function Oe(a){const s=a.trim().split(`
2
- `)[0],t=s.match(/^([^.!?]+[.!?])/);return t?t[1]:s.length>120?s.slice(0,120)+"…":s}function P(a){if(typeof a=="string")return a===""?'""':JSON.stringify(a);if(a===null)return"null";if(a===void 0)return"—";if(typeof a=="object"){const s=JSON.stringify(a);return s.length>60?s.slice(0,60)+"…":s}return String(a)}function Ae(){const[a,s]=x.useState(null),[t,l]=x.useState(null),[r,n]=x.useState(null),[i,p]=x.useState(null),[m,j]=x.useState(!1),[u,S]=x.useState(null),[h,N]=x.useState(null);if(x.useEffect(()=>{let c=!1;return Promise.all([window.api.otel.getConfig(),window.api.otel.status(),window.api.otel.configPath()]).then(([w,y,o])=>{c||(s(w),n(w),l(y),p(o))}).catch(w=>{console.warn("[telemetry] load failed:",w==null?void 0:w.message)}),()=>{c=!0}},[]),!r||!a)return e.jsx(M,{title:"loading…"});const f=JSON.stringify(r)!==JSON.stringify(a),b=(c,w)=>{S(null),n({...r,[c]:w})},C=async()=>{j(!0),S(null);try{const c=await window.api.otel.setConfig(r);!c.ok&&c.error&&S(c.error),s(c.config),n(c.config),l(c.status),N(Date.now())}catch(c){S(c instanceof Error?c.message:String(c))}finally{j(!1)}},E=()=>{S(null),n(a)};return e.jsxs("div",{className:"p-4 max-w-3xl space-y-5 text-sm",children:[e.jsxs("header",{className:"space-y-1",children:[e.jsx("h2",{className:"text-fg text-base font-medium",children:"Telemetry — OpenTelemetry export"}),e.jsx("p",{className:"text-fg-dim text-xs leading-relaxed",children:"When enabled, every classified transcript event (tool_use, todo_write, plan, usage, agent_spawn) is mirrored as a 0-duration OTLP/HTTP span. Point this at a local collector (Jaeger, Grafana Tempo, SigNoz, Honeycomb) for cross-session analysis."}),i&&e.jsxs("p",{className:"text-fg-faint text-[11px]",children:["stored at ",e.jsx("span",{className:"font-mono",children:i})]})]}),e.jsxs("section",{className:"border border-line rounded p-3 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-fg",children:"Export transcripts to OTEL"}),e.jsx("div",{className:"text-fg-faint text-xs",children:"Toggle off to disable all span emission immediately."})]}),e.jsx(H,{checked:r.enabled,onChange:c=>b("enabled",c),label:r.enabled?"on":"off"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"OTLP/HTTP traces endpoint"}),e.jsx("input",{type:"text",value:r.endpoint,onChange:c=>b("endpoint",c.target.value),placeholder:"http://localhost:4318/v1/traces",className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsxs("span",{className:"text-fg-dim text-xs",children:["Headers (newline-separated ",e.jsx("span",{className:"font-mono",children:"Key: Value"}),")"]}),e.jsx("textarea",{value:r.headers,onChange:c=>b("headers",c.target.value),placeholder:"x-honeycomb-team: YOUR_API_KEY",rows:3,className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("label",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"Service name"}),e.jsx("input",{type:"text",value:r.serviceName,onChange:c=>b("serviceName",c.target.value),placeholder:"session-manager",className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs"})]}),e.jsxs("div",{className:"flex items-start justify-between gap-3 pt-1",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-fg",children:"Include content (PII)"}),e.jsxs("div",{className:"text-fg-faint text-xs leading-relaxed",children:["Adds tool inputs, plan text, and agent prompts to span attributes. Off by default — matches upstream Claude Code's ",e.jsx("span",{className:"font-mono",children:"OTEL_LOG_USER_PROMPTS"})," opt-in."]})]}),e.jsx(H,{checked:r.includeContent,onChange:c=>b("includeContent",c),label:r.includeContent?"on":"off"})]})]}),t&&e.jsxs("section",{className:"border border-line rounded p-3 text-xs space-y-1",children:[e.jsx("div",{className:"text-fg-dim",children:"Runtime status"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-fg-faint",children:"enabled:"})," ",e.jsx("span",{className:t.enabled?"text-accent":"text-fg-dim",children:String(t.enabled)})]}),t.error&&e.jsxs("div",{className:"text-red-400 break-words",children:[e.jsx("span",{className:"text-fg-faint",children:"error:"})," ",t.error]}),!t.error&&t.enabled&&e.jsx("div",{className:"text-fg-faint",children:"spans batched and exported in the background. Verify by enabling and pointing at a local Jaeger."})]}),e.jsxs("footer",{className:"flex items-center gap-3 pt-2 border-t border-line",children:[e.jsx("button",{onClick:C,disabled:!f||m,className:"px-3 py-1 text-xs rounded bg-accent text-bg disabled:opacity-50 disabled:cursor-not-allowed",children:m?"saving…":"Save"}),e.jsx("button",{onClick:E,disabled:!f||m,className:"px-3 py-1 text-xs rounded border border-line text-fg-dim hover:text-fg disabled:opacity-50 disabled:cursor-not-allowed",children:"Revert"}),u&&e.jsx("span",{className:"text-red-400 text-xs",children:u}),!u&&h&&!f&&e.jsx("span",{className:"text-fg-faint text-xs",children:"saved"})]})]})}function Pe(){const{model:a,setModel:s}=q();return e.jsxs("div",{className:"p-4 max-w-3xl space-y-5 text-sm",children:[e.jsxs("header",{className:"space-y-1",children:[e.jsx("h2",{className:"text-fg text-base font-medium",children:"Session Manager preferences"}),e.jsx("p",{className:"text-fg-dim text-xs leading-relaxed",children:"Native app preferences, stored locally — not part of Claude Code's own settings."})]}),e.jsx("section",{className:"border border-line rounded p-3 space-y-3",children:e.jsxs("label",{className:"block space-y-1",children:[e.jsx("span",{className:"text-fg-dim text-xs",children:"Default model for raw sessions"}),e.jsx("select",{value:a,onChange:t=>s(t.target.value),className:"w-full bg-bg border border-line rounded px-2 py-1 text-fg font-mono text-xs",children:Y.map(t=>e.jsx("option",{value:t,children:t.charAt(0).toUpperCase()+t.slice(1)},t))}),e.jsx("span",{className:"text-fg-faint text-[11px]",children:"Used when opening a raw interactive session without an explicit per-launch override."})]})})]})}function Re(){const a=Z(),s=$(d=>d.tabs),t=$(d=>d.activeTabId),l=s.find(d=>d.id===t)??null,r=(l==null?void 0:l.cwd)??null,n=Q(d=>d.navFace),i=x.useRef(!1),p=x.useRef(n),[m,j]=x.useState(()=>n==="project"&&r?"project":"user"),[u,S]=x.useState("effective");x.useEffect(()=>{if(p.current!==n){if(p.current=n,i.current){i.current=!1;return}j(n==="project"&&r?"project":"user")}},[n,r]),x.useEffect(()=>{n==="project"&&(u==="telemetry"||u==="app")&&S("effective")},[n,u]);const h=d=>{i.current=!0,j(d)},N=re(F,a,r),f=N[m]??null,b=R(d=>d.files),C=R(d=>d.setDraft),E=R(d=>d.saveJson),c=R(d=>d.revert),[w,y]=x.useState(null),o=x.useMemo(()=>ne(le(b,N)),[b,N]),g=(d,A,O)=>{var _;const I=N[O??m];if(!I)return;y(null);const D=((_=b[I])==null?void 0:_.draftRaw)??"";let L={};if(D.trim())try{L=JSON.parse(D)}catch{L={}}const z=oe(L,d,A);C(I,JSON.stringify(z,null,2)+`
3
- `)};if(!a)return e.jsx(M,{title:"loading…"});const v=f?b[f]:null,T=d=>d!=="user"&&!r;return e.jsx(te,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(ee,{options:[{key:"effective",label:"Guided"},{key:"tree",label:"Tree"},{key:"raw",label:"Raw"},...n==="home"?[{key:"telemetry",label:"Telemetry"},{key:"app",label:"Session Manager"}]:[]],active:u,onChange:S}),u!=="telemetry"&&u!=="app"&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),e.jsx(ae,{scopes:F.scopes,active:m,onChange:h,annotate:d=>{if(T(d))return{exists:!1};const A=N[d];if(!A)return null;const O=b[A];return{exists:(O==null?void 0:O.exists)??!1,dirty:(O==null?void 0:O.dirty)??!1}}}),e.jsx("span",{className:"ml-3 text-fg-faint truncate",children:u==="effective"?`overrides → ${f??"—"}`:f??"—"})]}),e.jsx("div",{className:"flex-1"}),e.jsx("a",{href:"https://code.claude.com/docs/en/settings",target:"_blank",rel:"noreferrer",className:"text-fg-faint hover:text-fg-dim underline-offset-2 hover:underline",children:"schema reference ↗"})]}),footer:u!=="telemetry"&&u!=="app"&&f&&v?e.jsx(se,{dirty:v.dirty,busy:v.busy,parseError:w||v.parseError,lastSavedAt:v.lastSavedAt,leading:v.exists?null:e.jsx("span",{children:"file will be created on save"}),onSave:async()=>{y(null);const d=await E(f);d.ok||y(d.error??"save failed")},onRevert:()=>{y(null),c(f)}}):null,children:u==="telemetry"?e.jsx(Ae,{}):u==="app"?e.jsx(Pe,{}):T(m)?e.jsx(M,{title:"no active project",hint:"open a tab in a project directory to edit project or local settings"}):u==="effective"?e.jsx(ge,{node:o,targetScope:m,onOverride:g,schema:U()}):u==="tree"?e.jsx(ie,{node:o,targetScope:m,onOverride:g,schema:U()}):f&&v?e.jsx(X,{path:f,value:v.draftRaw,onChange:d=>{y(null),C(f,d)}}):e.jsx(M,{title:"resolving…"})})}const Ue=x.memo(Re);export{Ue as Settings};
@@ -1 +0,0 @@
1
- import{Y as n,a5 as V,K as t,aa as U,ai as k,ac as _,C as w,a8 as h,d as y}from"./index-TejhHSzN.js";import{P as C}from"./Panel-BhFD8Lqo.js";import{S as z,a as H}from"./ScopeSwitcher-DZ_3gEus.js";import{M as P}from"./MarkdownEditor-DQgfpSef.js";import{f as J,V as L}from"./Library-9E2UOIsm.js";import"./monaco-editor-BW5C4Iv1.js";function K(a){return a.split("/").pop()||a}function Y({activePath:a}){const[v,b]=n.useState([]),[g,i]=n.useState(null),[f,m]=n.useState({}),p=n.useRef(0);if(n.useEffect(()=>{if(p.current+=1,i(null),m({}),!a){b([]);return}const s=p.current;let c=!1;return window.api.config.parseImports(a).then(r=>{c||p.current!==s||(r.ok?b(r.imports):(b([]),V.error(r.error||"failed to parse @-imports")))}),()=>{c=!0}},[a]),v.length===0)return null;function j(s){if(g===s){i(null);return}if(i(s),!f[s]){const c=p.current;m(r=>({...r,[s]:{loading:!0,text:null,error:null}})),window.api.config.readText(s).then(r=>{p.current===c&&m(o=>({...o,[s]:{loading:!1,text:r.text,error:r.error}}))})}}return t.jsx("div",{className:"shrink-0 border-b border-line bg-bg-elev text-xs max-h-64 overflow-auto",children:v.map(s=>{const c=!s.ok||!s.exists,r=g===s.path,o=f[s.path];return t.jsxs("div",{className:"border-b border-line last:border-b-0","data-testid":"referenced-file-row",children:[t.jsxs("button",{type:"button",onClick:()=>j(s.path),className:"w-full flex items-center gap-2 px-3 py-1.5 text-left hover:bg-bg",children:[t.jsx("span",{className:`shrink-0 text-fg-faint transition-transform ${r?"rotate-90":""}`,children:"›"}),t.jsx("span",{className:"shrink-0 font-medium",children:K(s.path)}),t.jsx("span",{className:"text-fg-faint truncate flex-1",title:s.path,children:s.path}),t.jsxs("span",{className:"text-fg-faint shrink-0",children:[s.sizeBytes.toLocaleString()," bytes · ~",s.tokenEstimate.toLocaleString()," tokens"]}),c?t.jsx("span",{className:"shrink-0 px-1.5 py-0.5 rounded text-[10px] uppercase tracking-wide text-amber-400/90 border border-amber-400/30","data-testid":"referenced-file-missing",children:"missing"}):null]}),r?t.jsx("div",{className:"h-64 border-t border-line",children:!o||o.loading?t.jsx("div",{className:"px-3 py-2 text-fg-faint",children:"loading…"}):o.error?t.jsx("div",{className:"px-3 py-2 text-amber-400/90",children:o.error}):t.jsx(P,{path:s.path,value:o.text??"",onChange:()=>{},readOnly:!0})}):null]},s.path)})})}function $(a){return Math.round(a.length/4)}function q(){const a=U(),v=k(e=>e.tabs),b=k(e=>e.activeTabId),g=v.find(e=>e.id===b)??null,i=(g==null?void 0:g.cwd)??null,f=_(e=>e.navFace),m=n.useRef(!1),p=n.useRef(f),[j,s]=n.useState(()=>f==="project"&&i?"project":"user"),[c,r]=n.useState("installed");n.useEffect(()=>{if(p.current!==f){if(p.current=f,m.current){m.current=!1;return}s(f==="project"&&i?"project":"user")}},[f,i]);const o=n.useMemo(()=>{const e={};for(const u of w.scopes){const x=w.resolve(u,a??"",i);x&&(e[u]=x)}return e},[a,i]),d=o[j]??null,E=h(e=>e.files),R=h(e=>e.loadText),F=h(e=>e.setDraft),T=h(e=>e.saveText),D=h(e=>e.revert),M=h(e=>e.watchFile),A=h(e=>e.unwatchFile);n.useEffect(()=>{const e=Object.values(o).filter(Boolean);return e.forEach(u=>{R(u,!0),M(u)}),()=>{e.forEach(u=>A(u))}},[JSON.stringify(o)]);const[I,S]=n.useState(null);if(!a)return t.jsx(y,{title:"loading…"});if(c==="library")return t.jsx(C,{toolbar:t.jsx(L,{active:c,onChange:r,installedLabel:"Editor",libraryLabel:"Presets"}),children:t.jsx(J,{})});const l=d?E[d]:null,N=e=>e!=="user"&&!i,O=l?$(l.draftRaw):0,B=(l==null?void 0:l.draftRaw.length)??0;return t.jsx(C,{toolbar:t.jsxs(t.Fragment,{children:[t.jsx(L,{active:c,onChange:r,installedLabel:"Editor",libraryLabel:"Presets"}),t.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),t.jsx(H,{scopes:w.scopes,active:j,onChange:e=>{m.current=!0,s(e)},annotate:e=>{if(N(e))return{exists:!1};const u=o[e];if(!u)return null;const x=E[u];return{exists:(x==null?void 0:x.exists)??!1,dirty:(x==null?void 0:x.dirty)??!1}}}),t.jsx("span",{className:"ml-3 text-fg-faint truncate",children:d??"—"}),t.jsx("div",{className:"flex-1"}),t.jsxs("span",{className:"text-fg-faint",children:[B.toLocaleString()," chars · ~",O.toLocaleString()," tokens"]})]}),footer:d&&l?t.jsx(z,{dirty:l.dirty,busy:l.busy,parseError:I,lastSavedAt:l.lastSavedAt,leading:l.exists?null:t.jsx("span",{children:"file will be created on save"}),onSave:async()=>{S(null);const e=await T(d);e.ok||S(e.error??"save failed")},onRevert:()=>{S(null),D(d)}}):null,children:N(j)?t.jsx(y,{title:"no active project",hint:"open a tab in a project directory to edit project or local CLAUDE.md"}):d&&l?t.jsxs("div",{className:"h-full flex flex-col",children:[t.jsx(Y,{activePath:d}),t.jsx("div",{className:"flex-1 min-h-0",children:t.jsx(P,{path:d,value:l.draftRaw,onChange:e=>{S(null),F(d,e)}})})]}):t.jsx(y,{title:"resolving…"})})}const te=n.memo(q);export{te as SystemPrompt};