claude-code-session-manager 0.93.0 → 0.94.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 (67) hide show
  1. package/dist/assets/{DataModel-DDGx3qrn.js → DataModel-B0LDnnSL.js} +1 -1
  2. package/dist/assets/{History-CHBjYZyD.js → History-C685Kytt.js} +2 -2
  3. package/dist/assets/{Hooks-DG4c-Rzz.js → Hooks-CwLnp0Z_.js} +3 -3
  4. package/dist/assets/HostBilko-CwEHEKYk.js +1 -0
  5. package/dist/assets/{Library-CN1h5rAE.js → Library-BU9np05E.js} +25 -25
  6. package/dist/assets/{MarkdownEditor-DmBxrhdn.js → MarkdownEditor-B74ogK2f.js} +1 -1
  7. package/dist/assets/McpServers-BLM3ftzP.js +2 -0
  8. package/dist/assets/{Memory-Dk4uDCjg.js → Memory-DAP1t8bA.js} +6 -6
  9. package/dist/assets/{Permissions-BovobeZw.js → Permissions-3pGLJmxQ.js} +3 -3
  10. package/dist/assets/{Plugins-DvOf_B62.js → Plugins-Q1KoLEzn.js} +2 -2
  11. package/dist/assets/{ProvenanceBadge-Dutz_4OY.js → ProvenanceBadge-BnjBQiV9.js} +1 -1
  12. package/dist/assets/{SaveBar-CT5u6ZCJ.js → SaveBar-Zq2NfcPf.js} +1 -1
  13. package/dist/assets/{Scheduler-B7GSnZj5.js → Scheduler-D488ebKm.js} +9 -9
  14. package/dist/assets/{ScopeSwitcher-BUYDpz2v.js → ScopeSwitcher-Cnojv22D.js} +1 -1
  15. package/dist/assets/{Settings-DIRmr3tL.js → Settings-D5Lhj7ga.js} +3 -3
  16. package/dist/assets/{SkillReferenceGraph-CdGr6d3_.js → SkillReferenceGraph-BRDiE6Hv.js} +2 -2
  17. package/dist/assets/{Skills-BQOheQv4.js → Skills-BQDqp-EN.js} +2 -2
  18. package/dist/assets/{SystemPrompt-5LsimKbX.js → SystemPrompt-tFr19Od6.js} +1 -1
  19. package/dist/assets/{TagLibrary-DreLsT3n.js → TagLibrary-BjyrnaRE.js} +1 -1
  20. package/dist/assets/{TiptapBody-C9kmlBnI.js → TiptapBody-DGzSg3BO.js} +1 -1
  21. package/dist/assets/{Toggle-BKLCBu9A.js → Toggle-DzoROibf.js} +1 -1
  22. package/dist/assets/{index-Db_SK9rW.js → index-CCl4tz-u.js} +821 -821
  23. package/dist/assets/{settingsSchema-B5jBhSUP.js → settingsSchema-BYKVe1WM.js} +1 -1
  24. package/dist/index.html +1 -1
  25. package/package.json +6 -3
  26. package/scripts/README.md +3 -0
  27. package/src/main/__tests__/chat-cancel-terminal.test.cjs +5 -2
  28. package/src/main/__tests__/chat-exit-close-race.test.cjs +8 -2
  29. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +5 -2
  30. package/src/main/__tests__/intradayRefresh.test.cjs +39 -0
  31. package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +25 -0
  32. package/src/main/__tests__/opsErrorLog.test.cjs +22 -0
  33. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +21 -0
  34. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +14 -0
  35. package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +26 -0
  36. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +11 -1
  37. package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +11 -1
  38. package/src/main/__tests__/runVerify.test.cjs +12 -1
  39. package/src/main/__tests__/transcriptsUsageFor.test.cjs +112 -1
  40. package/src/main/build-info.json +4 -4
  41. package/src/main/chatRunner.cjs +45 -10
  42. package/src/main/git.cjs +9 -2
  43. package/src/main/historyAggregator.cjs +2 -19
  44. package/src/main/index.cjs +7 -8
  45. package/src/main/ipcSchemas.cjs +13 -3
  46. package/src/main/lib/__tests__/childWithLog.test.cjs +180 -0
  47. package/src/main/lib/__tests__/delegationReadiness.test.cjs +19 -0
  48. package/src/main/lib/__tests__/gitCacheBound.test.cjs +69 -0
  49. package/src/main/lib/agentPersonaSchema.cjs +2 -0
  50. package/src/main/lib/childWithLog.cjs +92 -51
  51. package/src/main/lib/delegationReadiness.cjs +3 -1
  52. package/src/main/lib/epicSpawnPlan.cjs +27 -8
  53. package/src/main/lib/epicTranscriptPath.cjs +5 -1
  54. package/src/main/lib/headTailBuffer.cjs +43 -0
  55. package/src/main/lib/intradayRefresh.cjs +33 -0
  56. package/src/main/lib/lruCache.cjs +39 -0
  57. package/src/main/lib/openExternalApp.cjs +27 -9
  58. package/src/main/lib/opsErrorLog.cjs +22 -0
  59. package/src/main/lib/promptSessionSchema.cjs +2 -0
  60. package/src/main/lib/rendererRecovery.cjs +141 -0
  61. package/src/main/lib/scheduleJobSchema.cjs +3 -0
  62. package/src/main/runVerify.cjs +3 -1
  63. package/src/main/scheduler.cjs +360 -257
  64. package/src/main/transcripts.cjs +54 -11
  65. package/src/preload/api.d.ts +3 -1
  66. package/dist/assets/HostBilko-DHXcpV2c.js +0 -1
  67. package/dist/assets/McpServers-Beb_HD6I.js +0 -2
@@ -37,6 +37,7 @@ function attachWindow(w) {
37
37
  }
38
38
 
39
39
  const { encodeCwd } = require('./lib/encodeCwd.cjs');
40
+ const { LRUCache } = require('./lib/lruCache.cjs');
40
41
  const { classifyLine } = require('./lib/classifyTranscriptLine.cjs');
41
42
  const { resolveEpicTranscriptPath } = require('./lib/epicTranscriptPath.cjs');
42
43
 
@@ -449,21 +450,32 @@ async function getBuffer(tabId) {
449
450
  // this size report null (omitted by the renderer) rather than a partial sum.
450
451
  const MAX_USAGE_FILE_BYTES = 64 * 1024 * 1024;
451
452
 
452
- /** Map<filePath, { mtimeMs, size, usage: {inputTokens, outputTokens} }> */
453
- const usageCache = new Map();
453
+ /** Max distinct transcripts whose running totals stay cached. */
454
+ const USAGE_CACHE_MAX = 200;
455
+
456
+ /**
457
+ * LRU<filePath, { ino, size, mtimeMs, readOffset, usage }>. `readOffset` is the
458
+ * byte just past the last complete (newline-terminated) line already summed, so
459
+ * the next call only parses [readOffset, size). The full parse keeps no
460
+ * de-dup state (every usage event is summed), so none is cached here.
461
+ */
462
+ const usageCache = new LRUCache(USAGE_CACHE_MAX);
454
463
 
455
464
  /**
456
465
  * Sum `usage` events out of one session's JSONL transcript — same
457
466
  * classifyLine()/field-name resolution live.ts's ingest uses for its running
458
467
  * per-tab totals (input_tokens/output_tokens, snake_case on the wire).
459
- * Cached by file mtime so repeat calls for an unchanged transcript are a
460
- * single fs.stat.
468
+ * Append-only tail parse: when the inode matches and the file has not shrunk,
469
+ * only the new bytes are read (positional fd.read) and a trailing partial line
470
+ * waits until completed; truncation / inode change → full re-parse.
471
+ * Cost per call: O(appended bytes) time and space; O(file) only on cold/reset.
461
472
  */
462
473
  async function usageForOne(filePath) {
463
474
  const stat = await fsp.stat(filePath).catch(() => null);
464
475
  if (!stat) return null;
465
476
  const cached = usageCache.get(filePath);
466
- if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
477
+ const canTail = !!cached && cached.ino === stat.ino && stat.size >= cached.readOffset;
478
+ if (canTail && cached.size === stat.size && cached.mtimeMs === stat.mtimeMs) {
467
479
  return cached.usage;
468
480
  }
469
481
  if (stat.size > MAX_USAGE_FILE_BYTES) {
@@ -475,11 +487,33 @@ async function usageForOne(filePath) {
475
487
  });
476
488
  return null;
477
489
  }
478
- const text = await fsp.readFile(filePath, 'utf8').catch(() => null);
479
- if (text === null) return null;
480
- let inputTokens = 0;
481
- let outputTokens = 0;
482
- for (const line of text.split('\n')) {
490
+ const start = canTail ? cached.readOffset : 0;
491
+ let inputTokens = canTail ? cached.usage.inputTokens : 0;
492
+ let outputTokens = canTail ? cached.usage.outputTokens : 0;
493
+ const want = stat.size - start;
494
+ let buf = Buffer.alloc(0);
495
+ if (want > 0) {
496
+ let fd;
497
+ try {
498
+ fd = await fsp.open(filePath, 'r');
499
+ buf = Buffer.alloc(want);
500
+ let got = 0;
501
+ while (got < want) {
502
+ const { bytesRead } = await fd.read(buf, got, want - got, start + got);
503
+ if (bytesRead === 0) break;
504
+ got += bytesRead;
505
+ }
506
+ buf = buf.subarray(0, got);
507
+ } catch {
508
+ return null;
509
+ } finally {
510
+ await fd?.close().catch(() => {});
511
+ }
512
+ }
513
+ // Consume only complete lines; a trailing partial line is re-read next call.
514
+ const lastNl = buf.lastIndexOf(0x0a);
515
+ const complete = lastNl === -1 ? '' : buf.subarray(0, lastNl + 1).toString('utf8');
516
+ for (const line of complete.split('\n')) {
483
517
  if (!line) continue;
484
518
  let obj;
485
519
  try {
@@ -496,7 +530,13 @@ async function usageForOne(filePath) {
496
530
  }
497
531
  }
498
532
  const usage = { inputTokens, outputTokens };
499
- usageCache.set(filePath, { mtimeMs: stat.mtimeMs, size: stat.size, usage });
533
+ usageCache.set(filePath, {
534
+ ino: stat.ino,
535
+ size: stat.size,
536
+ mtimeMs: stat.mtimeMs,
537
+ readOffset: start + lastNl + 1,
538
+ usage,
539
+ });
500
540
  return usage;
501
541
  }
502
542
 
@@ -562,6 +602,9 @@ module.exports = {
562
602
  // Test-only accessor onto the raw Subscription object (its lineIndex in
563
603
  // particular) — asserting a memory ceiling requires inspecting what's
564
604
  // actually held, not just what a read API returns.
605
+ __usageCacheForTest: usageCache,
606
+ __usageForOneForTest: usageForOne,
607
+ __usageCacheMaxForTest: USAGE_CACHE_MAX,
565
608
  __getSubForTest: (tabId) => subs.get(tabId),
566
609
  // Test-only: run a live (emit:true) flush directly against a subscription,
567
610
  // without going through the chokidar watcher — lets batching/IPC-shape
@@ -1,3 +1,5 @@
1
+ import type { PromptSession } from '../renderer/state/promptSessions';
2
+
1
3
  export interface BuildTarget {
2
4
  registry: string;
3
5
  packageName: string;
@@ -2124,7 +2126,7 @@ export interface PromptSessionsCreateEpicPayload {
2124
2126
 
2125
2127
  export interface PromptSessionsCreateEpicResult {
2126
2128
  epicId: string;
2127
- session: Record<string, unknown>;
2129
+ session: PromptSession;
2128
2130
  }
2129
2131
 
2130
2132
  // ─────────────────────────────────── PromptSessions create-worktree (main-side createEpicWorktree)
@@ -1 +0,0 @@
1
- import{ay as i,aL as J,aV as P,aK as m,$ as Y,aM as Q,aj as t,l as $,aF as W}from"./index-Db_SK9rW.js";import"./monaco-editor-BW5C4Iv1.js";function X(r){return r.hasMarketingPage?r.packagePrivate&&!r.packageHomepage?{kind:"private-needs-confirm"}:{kind:"ready"}:{kind:"no-marketing-page"}}const Z=["home","marketing","feature","architecture"],ee={home:"Home page",marketing:"Marketing page",feature:"Feature page",architecture:"Architecture page"};function I(r){return ee[r]}function D(r){const n=r.find(l=>l.subpath==="");return Z.map(l=>{const p=r.find(h=>h.source.kind==="project-page-lens"&&h.source.lens===l);return p?{lens:l,status:p.subpath===""?"root":"hosted",subpath:p.subpath,documentId:p.id}:!n&&l==="marketing"?{lens:l,status:"root",subpath:"",documentId:null}:{lens:l,status:"available",subpath:l,documentId:null}})}function te(r){return r.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"project"}const j="bilko-host-publisher",se="bilko-host-publisher",ne=[{value:"home",label:"Home lens"},{value:"marketing",label:"Marketing lens"},{value:"feature",label:"Feature lens"},{value:"architecture",label:"Architecture lens"}];function ae(r,n){for(const l of Object.values(r))if(l.cwd===n&&l.tag===j&&l.status==="active")return l;return null}function _(r){W(r),window.dispatchEvent(new CustomEvent("sm:navigate",{detail:"terminal"}))}function oe(){const r=J(),n=(r==null?void 0:r.cwd)??null,l=P(e=>e.sessions),p=P(e=>e.createPromptSession),h=P(e=>e.approveProposed),[o,C]=i.useState(null),[R,v]=i.useState(!1),[b,k]=i.useState(""),[E,H]=i.useState(!1),[M,B]=i.useState(!1),[u,L]=i.useState(null),[N,A]=i.useState(""),[f,T]=i.useState(""),[y,F]=i.useState("feature");i.useEffect(()=>{let e=!1;return window.api.agents.listPersonas().then(a=>{if(e)return;const s=a.find(g=>g.name===se);L(s?{name:s.name,description:s.description}:null)}).catch(()=>{e||L(null)}),()=>{e=!0}},[]);const c=i.useCallback(()=>{n&&(v(!1),window.api.bilkoHost.get(n).then(e=>{C(e),k(a=>{var s;return a||((s=e.bundleManifest)==null?void 0:s.slug)||e.defaultSlug}),v(!0)}).catch(e=>{v(!0),m.error(`Could not load bilko-host status: ${e instanceof Error?e.message:String(e)}`)}))},[n]);i.useEffect(()=>{C(null),k(""),H(!1),c()},[c]);const x=n?ae(l,n):null,O=i.useCallback(()=>{!n||!b||(B(!0),window.api.bilkoHost.prepareBundle(n,b).then(()=>c()).catch(e=>m.error(`Could not prepare bundle: ${e instanceof Error?e.message:String(e)}`)).finally(()=>B(!1)))},[n,b,c]),z=i.useCallback(()=>{if(!n)return;const e=te(N).replace(/^-+|-+$/g,"");if(!e||!f.trim()){m.error("A sub-path and a title are required.");return}const a={kind:"project-page-lens",lens:y};window.api.bilkoHost.addDocument(n,e,f.trim(),a).then(()=>{A(""),T(""),c()}).catch(s=>m.error(`Could not add document: ${s instanceof Error?s.message:String(s)}`))},[n,N,f,y,c]),G=i.useCallback((e,a)=>{n&&window.api.bilkoHost.addDocument(n,a,I(e),{kind:"project-page-lens",lens:e}).then(()=>c()).catch(s=>m.error(`Could not add ${e} page: ${s instanceof Error?s.message:String(s)}`))},[n,c]),K=i.useCallback(async()=>{if(!n||!o)return;const e=D(o.documents).filter(a=>a.status==="available");for(const a of e)try{await window.api.bilkoHost.addDocument(n,a.subpath,I(a.lens),{kind:"project-page-lens",lens:a.lens})}catch(s){m.error(`Could not add ${a.lens} page: ${s instanceof Error?s.message:String(s)}`)}c()},[n,o,c]),U=i.useCallback(e=>{n&&window.api.bilkoHost.removeDocument(n,e).then(()=>c()).catch(a=>m.error(`Could not remove document: ${a instanceof Error?a.message:String(a)}`))},[n,c]),V=i.useCallback(async()=>{if(!n||!b)return;if(x){_(x.id);return}const e=`Publish this project to bilko.run as a static-path listing, slug "${b}". Bundle is at session-manager-operations/bilko-host/dist/ (prepare it first via Prepare Bundle if it's missing or stale) — it may contain multiple documents (a root page plus sub-paths); publish the whole dist/ tree as one static-path app.`,{goalText:a,openingPrompt:s}=Y({title:"",goal:e,tag:j,agentName:u==null?void 0:u.name,agentDescription:(u==null?void 0:u.description)??void 0}),g=u?await p(n,a,j,"HostBilko",u.name):await p(n,a,j,"HostBilko");h(g.id,"HostBilko"),Q.getState().send({tabId:g.id,sessionId:g.claudeSessionId,cwd:n,prompt:s}),_(g.id)},[n,b,x,p,h,u]);if(!n)return t.jsx($,{title:"Open a project to host it on Bilko.run"});if(!R||!o)return null;const w=X(o);if(w.kind==="no-marketing-page")return t.jsx($,{title:"No Marketing page yet",hint:"Generate this project's Project Pages from Project Home first — the root document publishes the Marketing lens."});const d=o.publishState,q=(d==null?void 0:d.status)??(o.bundleManifest?"bundle-ready":"not-published"),S=w.kind==="ready"||E;return t.jsxs("div",{className:"max-w-2xl space-y-4",children:[t.jsxs("div",{className:"rounded-card border border-line bg-bg-hi p-5 space-y-4",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("div",{children:[t.jsx("div",{className:"font-serif text-lg text-fg",children:o.projectName}),t.jsxs("div",{className:"text-xs text-fg-faint mt-0.5",children:["Status: ",t.jsx("span",{className:"font-mono",children:q}),o.bundleStale&&o.bundleManifest&&t.jsx("span",{className:"ml-2 text-accent",children:"bundle out of date — Prepare Bundle again"})]})]}),(d==null?void 0:d.status)==="published"&&d.url&&t.jsx("a",{href:d.url,target:"_blank",rel:"noreferrer",className:"text-xs text-accent hover:underline",children:d.url})]}),w.kind==="private-needs-confirm"&&!E&&t.jsxs("div",{className:"rounded-md border border-line bg-bg p-3 text-xs text-fg-dim",children:["This project's package.json is marked private with no public homepage. Confirm you want to publish it to bilko.run anyway.",t.jsx("button",{type:"button",onClick:()=>H(!0),className:"mt-2 block rounded-md bg-accent px-3 py-1.5 text-xs font-semibold text-bg-hi hover:bg-accent-dark",children:"Yes, this can be public"})]}),S&&t.jsxs(t.Fragment,{children:[t.jsxs("label",{className:"block text-xs text-fg-faint",children:["Slug (bilko.run/projects/<slug>/)",t.jsx("input",{value:b,onChange:e=>k(e.target.value.toLowerCase()),className:"mt-1 block w-full rounded-md border border-line bg-bg px-2.5 py-1.5 text-sm font-mono text-fg"})]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("button",{type:"button",onClick:O,disabled:M,className:"rounded-md border border-line bg-bg px-3.5 py-1.5 text-xs font-semibold text-fg hover:bg-bg-hi disabled:opacity-50",children:M?"Preparing…":"Prepare Bundle"}),t.jsx("button",{type:"button",onClick:()=>{V().catch(e=>{m.error(e instanceof Error?e.message:String(e))})},disabled:!o.bundleManifest,title:o.bundleManifest?void 0:"Prepare a bundle first",className:"rounded-md bg-accent px-3.5 py-1.5 text-xs font-semibold text-bg-hi hover:bg-accent-dark disabled:opacity-50",children:x?"View publish in progress":"Publish"})]}),o.bundleManifest&&t.jsxs("div",{className:"text-[11px] text-fg-faint font-mono",children:["bundle: ",(o.bundleManifest.bundle.sizeBytesGz/1024).toFixed(1)," KB gz ·"," ",o.bundleManifest.bundle.fileCount," document",o.bundleManifest.bundle.fileCount===1?"":"s"," · built"," ",new Date(o.bundleManifest.builtAt).toLocaleString()," · ",o.bundleManifest.gitSha]}),(d==null?void 0:d.status)==="publish-failed"&&d.lastError&&t.jsxs("div",{className:"text-xs text-accent",children:["Last publish failed: ",d.lastError]})]})]}),S&&(()=>{const e=D(o.documents),a=e.filter(s=>s.status==="available").length;return t.jsxs("div",{className:"rounded-card border border-line bg-bg-hi p-5 space-y-3",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("div",{className:"font-serif text-base text-fg",children:"Project Pages"}),a>1&&t.jsxs("button",{type:"button",onClick:K,className:"text-xs text-accent hover:underline",children:["Host all ",a," remaining"]})]}),t.jsxs("p",{className:"text-xs text-fg-faint",children:["This project generates 4 pages (Home / Marketing / Feature / Architecture). Marketing is the project's root (bilko.run/projects/",b||"<slug>","/); host any of the others as their own sub-page if you want them public too."]}),t.jsx("ul",{className:"space-y-1.5",children:e.map(s=>t.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-md border border-line bg-bg px-3 py-2 text-xs",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsx("div",{className:"text-fg capitalize",children:s.lens}),t.jsx("div",{className:"text-fg-faint font-mono truncate",children:s.status==="root"?"(project root)":`/${s.subpath}/`})]}),s.status==="available"?t.jsxs("button",{type:"button",onClick:()=>G(s.lens,s.subpath),className:"shrink-0 rounded-md border border-line px-2 py-1 text-fg hover:bg-bg-hi",children:["+ Host as /",s.subpath,"/"]}):t.jsx("span",{className:"shrink-0 text-fg-faint",children:s.status==="root"?"root":"hosted"})]},s.lens))})]})})(),S&&t.jsxs("div",{className:"rounded-card border border-line bg-bg-hi p-5 space-y-3",children:[t.jsx("div",{className:"font-serif text-base text-fg",children:"Hosted documents"}),t.jsx("p",{className:"text-xs text-fg-faint",children:"One project, one Bilko listing — add as many explanatory pages as you want under it, each at its own sub-path. Removing one here takes it down on the next Publish."}),t.jsx("ul",{className:"space-y-1.5",children:o.documents.map(e=>t.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-md border border-line bg-bg px-3 py-2 text-xs",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsx("div",{className:"text-fg truncate",children:e.title}),t.jsxs("div",{className:"text-fg-faint font-mono truncate",children:[e.subpath===""?"(root)":`/${e.subpath}/`," · ",e.url]})]}),e.subpath!==""&&t.jsx("button",{type:"button",onClick:()=>U(e.id),title:"Remove — takes effect on the next Publish",className:"shrink-0 rounded-md border border-line px-2 py-1 text-fg-faint hover:text-accent hover:border-accent/40",children:"Remove"})]},e.id))}),t.jsxs("div",{className:"rounded-md border border-line bg-bg p-3 space-y-2",children:[t.jsx("div",{className:"text-[11px] font-semibold uppercase tracking-wide text-fg-faint",children:"Add a document"}),t.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[t.jsx("input",{value:N,onChange:e=>A(e.target.value),placeholder:"sub-path, e.g. special-doc/01",className:"rounded-md border border-line bg-bg-hi px-2.5 py-1.5 text-xs font-mono text-fg"}),t.jsx("input",{value:f,onChange:e=>T(e.target.value),placeholder:"Title",className:"rounded-md border border-line bg-bg-hi px-2.5 py-1.5 text-xs text-fg"})]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("select",{value:y,onChange:e=>F(e.target.value),className:"rounded-md border border-line bg-bg-hi px-2.5 py-1.5 text-xs text-fg",children:ne.map(e=>t.jsx("option",{value:e.value,children:e.label},e.value))}),t.jsx("button",{type:"button",onClick:z,className:"rounded-md border border-line bg-bg-hi px-3.5 py-1.5 text-xs font-semibold text-fg hover:bg-bg",children:"Add document"})]})]})]})]})}const le=i.memo(oe);export{le as HostBilko};
@@ -1,2 +0,0 @@
1
- import{aj as e,ay as c,aQ as oe,aL as ie,aS as ce,aN as N,l as O,u as $,q as de,a as Z,aK as q}from"./index-Db_SK9rW.js";import{S as xe}from"./SaveBar-CT5u6ZCJ.js";import{S as Y}from"./ScopeSwitcher-BUYDpz2v.js";import{P as G}from"./ProvenanceBadge-Dutz_4OY.js";import{M as ue,V as D}from"./Library-CN1h5rAE.js";import"./monaco-editor-BW5C4Iv1.js";const pe={live:"bg-emerald-400",idle:"bg-amber-400",offline:"bg-fg-faint",attention:"bg-accent",paused:"bg-zinc-500"},fe={sm:"w-1.5 h-1.5",md:"w-2 h-2"},me={on:"live",off:"offline",warn:"attention",live:"live",idle:"idle"};function W({state:n,kind:t,pulse:a=!1,size:d="sm",className:p="",title:b,"aria-label":o}){const j=n??(t?me[t]:"idle"),r=pe[j],h=fe[d],x=a?"animate-pulse":"",u=o??b??j;return e.jsx("span",{role:"img","aria-label":u,className:`inline-block rounded-full ${h} ${r} ${x} ${p}`.trim(),title:b})}const ge={failed:"Failed","needs-auth":"Needs auth",pending:"Pending approval"};function H(n,t){const a=t!=null&&t.ok?t.servers.find(d=>d.name===n):void 0;return!a||a.status==="unknown"?{state:"unprobed",label:"Not checked",probeStatus:(a==null?void 0:a.status)??null,badgeTone:"dim",dotState:"offline"}:a.status==="connected"?{state:"ready",label:"Ready",probeStatus:a.status,badgeTone:"good",dotState:"live"}:{state:"not-ready",label:ge[a.status],probeStatus:a.status,badgeTone:"warn",dotState:"attention"}}const Q=(n,t)=>({type:"mcp",name:n,command:t.command,args:t.args,url:t.url}),he=["stdio","http","streamable-http","sse","ws"],be=new Set(["workspace"]),je=new Set(["ide","tasks"]);function ve(n,t,a){return n==="user"?`${t}/.claude.json`:a?`${a}/.mcp.json`:null}function ye(n){if(n.trim()==="")return{full:{},servers:{},err:null};try{const t=JSON.parse(n),a=t.mcpServers??{};return{full:t,servers:a,err:null}}catch(t){return{full:{},servers:{},err:t.message}}}function Ne(n,t){return JSON.stringify({...n,mcpServers:t},null,2)+`
2
- `}function we(n){let t=Object.keys(n).length+1,a=`server-${t}`;for(;n[a];)t+=1,a=`server-${t}`;return a}function Se(){const n=oe(),t=ie(),a=(t==null?void 0:t.cwd)??null,d=ce(s=>s.navFace),p=c.useRef(!1),b=c.useRef(d),[o,j]=c.useState(()=>d==="project"&&a?"project":"user"),[r,h]=c.useState(null),[x,u]=c.useState("installed"),[w,_]=c.useState("");c.useEffect(()=>{if(b.current!==d){if(b.current=d,p.current){p.current=!1;return}j(d==="project"&&a?"project":"user")}},[d,a]);const f=c.useMemo(()=>n?ve(o,n,a):null,[n,o,a]),k=N(s=>s.files),l=N(s=>s.loadJson),v=N(s=>s.setDraft),m=N(s=>s.saveJson),I=N(s=>s.revert),T=N(s=>s.watchFile),X=N(s=>s.unwatchFile);c.useEffect(()=>{if(f)return k[f]||l(f),T(f),()=>X(f)},[f]);const[ee,R]=c.useState(null),[J,K]=c.useState(null),[B,z]=c.useState(!1),F=c.useRef(0),A=c.useRef(!0);c.useEffect(()=>()=>{A.current=!1},[]);const V=async()=>{const s=++F.current;z(!0);try{const i=await window.api.mcp.status();if(!A.current||s!==F.current)return;K(i),i.ok||q.error(i.error??"MCP status probe failed")}catch(i){if(!A.current||s!==F.current)return;K(null),q.error(i.message||"MCP status probe failed")}finally{A.current&&s===F.current&&z(!1)}};if(c.useEffect(()=>{V()},[]),!n)return e.jsx(O,{title:"loading…"});if(x==="library")return e.jsx($,{toolbar:e.jsx(D,{active:x,onChange:u}),children:e.jsx(ue,{})});if(o==="project"&&!a)return e.jsx($,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(D,{active:x,onChange:u}),e.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),e.jsx(Y,{scopes:["user","project"],active:o,onChange:s=>{p.current=!0,j(s)}})]}),children:e.jsx(O,{title:"no active project"})});if(!f)return e.jsx(O,{title:"loading…"});const y=k[f],{full:te,servers:g,err:se}=y?ye(y.draftRaw):{full:{},servers:{},err:null},L=Object.keys(g).sort(),M=r?g[r]:null,P=s=>{R(null),v(f,Ne(te,s))},ae=()=>{const s=we(g);P({...g,[s]:{type:"stdio",command:"",args:[]}}),h(s)},le=s=>{const i={...g};delete i[s],P(i),r===s&&h(null)},ne=(s,i)=>{if(!i||i===s||g[i])return;const S={};for(const C of Object.keys(g))S[C===s?i:C]=g[C];P(S),h(i)},re=(s,i)=>{P({...g,[s]:i})};return e.jsx($,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(D,{active:x,onChange:u}),e.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),e.jsx(Y,{scopes:["user","project"],active:o,onChange:s=>{p.current=!0,j(s)}}),e.jsxs("span",{className:"ml-3 px-1.5 py-0.5 text-[10px] rounded border border-line text-fg-faint",children:[L.length," server",L.length===1?"":"s"]}),e.jsx("span",{className:"ml-2 text-fg-faint truncate",children:f}),e.jsx("div",{className:"flex-1"}),r&&M&&e.jsx(G,{scope:o,input:Q(r,M),className:"mr-2"}),e.jsx("button",{onClick:V,disabled:B,className:"px-2 py-0.5 text-xs border border-line rounded text-fg-dim hover:text-fg hover:bg-bg-hi disabled:opacity-50 mr-2",children:B?"checking…":"⟳ test connections"}),e.jsx("button",{onClick:ae,className:"px-2 py-0.5 text-xs border border-line rounded text-fg-dim hover:text-fg hover:bg-bg-hi",children:"+ new server"})]}),footer:y?e.jsx(xe,{dirty:y.dirty,busy:y.busy,parseError:ee||se||y.parseError,lastSavedAt:y.lastSavedAt,onSave:async()=>{R(null);const s=await m(f);s.ok||R(s.error??"save failed")},onRevert:()=>{R(null),I(f)}}):null,children:e.jsx(de,{sidebar:e.jsxs("div",{className:"py-2",children:[e.jsx("div",{className:"px-2 pb-1",children:e.jsx("input",{value:w,onChange:s=>_(s.target.value),placeholder:"filter…",className:"w-full bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg"})}),L.length===0?e.jsx("div",{className:"px-3 py-1 text-xs text-fg-faint italic",children:"no servers"}):L.filter(s=>!w||s.toLowerCase().includes(w.toLowerCase())).map(s=>{var C;const i=H(s,J),S=(C=g[s].description)==null?void 0:C.trim();return e.jsxs("button",{onClick:()=>h(s),className:`w-full text-left px-3 py-1 text-xs flex flex-col gap-0.5 ${r===s?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[e.jsxs("span",{className:"flex items-center gap-2 justify-between w-full",children:[e.jsxs("span",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(W,{state:i.dotState,title:i.label}),e.jsx("span",{className:"truncate",children:s})]}),e.jsxs("span",{className:"ml-2 flex items-center gap-2 shrink-0",children:[e.jsx(Z,{tone:i.badgeTone,children:i.label}),e.jsx(G,{interactive:!1,scope:o,input:Q(s,g[s])}),e.jsx("span",{className:"text-fg-faint",children:g[s].type??"stdio"})]})]}),S?e.jsx("span",{className:"pl-5 text-fg-faint truncate",title:S,children:S}):null]},s)})]}),detail:r&&M?e.jsx(Ce,{name:r,server:M,connection:H(r,J),onTestConnection:V,testing:B,onRename:s=>ne(r,s),onChange:s=>re(r,s),onRemove:()=>le(r)}):e.jsx(O,{title:"select a server or click + new"})})})}const Le=c.memo(Se);function Ce({name:n,server:t,connection:a,onTestConnection:d,testing:p,onRename:b,onChange:o,onRemove:j}){var k;const r=t.type??"stdio",h=be.has(n),x=je.has(n),u=(k=t.permissions)==null?void 0:k.tools,w=u===void 0?"inherit":u==="allow"?"allow":u==="deny"?"deny":"list",_=Array.isArray(u)?u:[],f=(t.disabledTools??[]).join(", ");return e.jsxs("div",{className:"p-4 space-y-4 max-w-2xl",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(W,{state:a.dotState,size:"md",title:a.label}),e.jsx(Z,{tone:a.badgeTone,children:a.label}),e.jsx("button",{onClick:d,disabled:p,className:"ml-auto px-2 py-0.5 text-xs border border-line rounded text-fg-dim hover:text-fg hover:bg-bg-hi disabled:opacity-50",children:p?"checking…":"test connection"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20",children:"name"}),e.jsx("input",{defaultValue:n,onBlur:l=>b(l.target.value.trim()),className:"flex-1 bg-bg-elev border border-line rounded px-2 py-1 text-xs text-fg font-mono"}),e.jsx("button",{onClick:j,className:"text-xs text-fg-faint hover:text-red-400 px-2 py-1 border border-line rounded",children:"delete"})]}),e.jsx(E,{label:"description",value:t.description??"",onChange:l=>o({...t,description:l||void 0}),placeholder:"what this server does…"}),h?e.jsxs("div",{className:"text-xs px-2 py-1 border border-red-500/50 rounded text-red-300 bg-red-500/5",children:["⚠ ",e.jsx("span",{className:"font-mono",children:n})," is a reserved name — Claude Code will refuse to load this server (v2.1.128+)."]}):x?e.jsxs("div",{className:"text-xs px-2 py-1 border border-yellow-600/50 rounded text-yellow-200 bg-yellow-500/5",children:["⚠ ",e.jsx("span",{className:"font-mono",children:n})," collides with a commonly-bundled MCP name; expect surprises in other tools."]}):null,e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20",children:"type"}),e.jsx("select",{value:r,onChange:l=>o({...t,type:l.target.value}),className:"bg-bg-elev border border-line rounded px-2 py-1 text-xs text-fg",children:he.map(l=>e.jsx("option",{value:l,children:l},l))}),r==="sse"?e.jsx("span",{className:"text-xs text-yellow-400/80",children:"sse is deprecated — prefer streamable-http"}):null]}),r==="stdio"?e.jsxs(e.Fragment,{children:[e.jsx(E,{label:"command",value:t.command??"",onChange:l=>o({...t,command:l}),placeholder:"npx / node / python …"}),e.jsx(E,{label:"args",value:(t.args??[]).join(" "),onChange:l=>o({...t,args:l.split(/\s+/).filter(Boolean)}),placeholder:"space-separated args"}),e.jsx(U,{label:"env",value:t.env??{},onChange:l=>o({...t,env:l})})]}):e.jsxs(e.Fragment,{children:[e.jsx(E,{label:"url",value:t.url??"",onChange:l=>o({...t,url:l}),placeholder:"https://…"}),e.jsx(U,{label:"headers",value:t.headers??{},onChange:l=>o({...t,headers:l})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20",children:"alwaysLoad"}),e.jsxs("label",{className:"flex items-center gap-2 text-xs text-fg",children:[e.jsx("input",{type:"checkbox",checked:t.alwaysLoad===!0,onChange:l=>o({...t,alwaysLoad:l.target.checked||void 0})}),e.jsx("span",{className:"text-fg-dim",children:"bypass tool-search deferral (v2.1.121+)"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20",children:"enabled"}),e.jsxs("label",{className:"flex items-center gap-2 text-xs text-fg",children:[e.jsx("input",{type:"checkbox",checked:t.enabled!==!1,onChange:l=>o({...t,enabled:l.target.checked?void 0:!1})}),e.jsx("span",{className:"text-fg-dim",children:"load this server in new sessions"})]})]}),e.jsx(E,{label:"disabledTools",value:f,onChange:l=>{const v=l.split(",").map(m=>m.trim()).filter(Boolean);o({...t,disabledTools:v.length?v:void 0})},placeholder:"comma-separated tool names to hide"}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20 pt-1",children:"permissions"}),e.jsxs("div",{className:"flex-1 space-y-1",children:[e.jsxs("select",{value:w,onChange:l=>{const v=l.target.value,m={...t};if(v==="inherit"){if(m.permissions){const{tools:I,...T}=m.permissions;m.permissions=Object.keys(T).length?T:void 0}}else v==="list"?m.permissions={...m.permissions??{},tools:[]}:m.permissions={...m.permissions??{},tools:v};o(m)},className:"bg-bg-elev border border-line rounded px-2 py-1 text-xs text-fg",children:[e.jsx("option",{value:"inherit",children:"inherit (default)"}),e.jsx("option",{value:"allow",children:"allow all tools"}),e.jsx("option",{value:"deny",children:"deny all tools"}),e.jsx("option",{value:"list",children:"allowlist…"})]}),w==="list"?e.jsx("input",{value:_.join(", "),onChange:l=>{const v=l.target.value.split(",").map(m=>m.trim()).filter(Boolean);o({...t,permissions:{...t.permissions??{},tools:v}})},placeholder:"comma-separated tool names",className:"w-full bg-bg-elev border border-line rounded px-2 py-1 text-xs text-fg font-mono"}):null]})]})]})}function E({label:n,value:t,onChange:a,placeholder:d}){return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20",children:n}),e.jsx("input",{value:t,onChange:p=>a(p.target.value),placeholder:d,className:"flex-1 bg-bg-elev border border-line rounded px-2 py-1 text-xs text-fg font-mono"})]})}function U({label:n,value:t,onChange:a}){const[d,p]=c.useState(""),[b,o]=c.useState(""),j=Object.entries(t);return e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx("label",{className:"text-xs text-fg-faint w-20 pt-1",children:n}),e.jsxs("div",{className:"flex-1 space-y-1",children:[j.map(([r,h])=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{value:r,onChange:x=>{const u={...t};delete u[r],u[x.target.value]=h,a(u)},className:"w-32 bg-bg-elev border border-line rounded px-2 py-0.5 text-xs text-fg font-mono"}),e.jsx("input",{value:h,onChange:x=>a({...t,[r]:x.target.value}),className:"flex-1 bg-bg-elev border border-line rounded px-2 py-0.5 text-xs text-fg font-mono"}),e.jsx("button",{onClick:()=>{const x={...t};delete x[r],a(x)},className:"text-fg-faint hover:text-red-400 text-xs px-1",children:"×"})]},r)),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{value:d,onChange:r=>p(r.target.value),placeholder:"key",className:"w-32 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg-dim font-mono"}),e.jsx("input",{value:b,onChange:r=>o(r.target.value),placeholder:"value",className:"flex-1 bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg-dim font-mono"}),e.jsx("button",{onClick:()=>{d.trim()&&(a({...t,[d.trim()]:b}),p(""),o(""))},className:"px-2 text-xs border border-line rounded text-fg-dim hover:text-fg hover:bg-bg-hi",children:"+"})]})]})]})}export{Le as McpServers,we as nextServerName};