claude-code-session-manager 0.92.0 → 0.93.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 (75) hide show
  1. package/dist/assets/DataModel-DDGx3qrn.js +1 -0
  2. package/dist/assets/{History-BB6wpf02.js → History-CHBjYZyD.js} +2 -2
  3. package/dist/assets/{Hooks-zQZH56Sv.js → Hooks-DG4c-Rzz.js} +3 -3
  4. package/dist/assets/{HostBilko-CW0pHoPS.js → HostBilko-DHXcpV2c.js} +1 -1
  5. package/dist/assets/{Library-DrGdaz9N.js → Library-CN1h5rAE.js} +1 -1
  6. package/dist/assets/{MarkdownEditor-H1ytN4Tk.js → MarkdownEditor-DmBxrhdn.js} +1 -1
  7. package/dist/assets/{McpServers-CYSRCI-j.js → McpServers-Beb_HD6I.js} +2 -2
  8. package/dist/assets/{Memory-zMNpJyRU.js → Memory-Dk4uDCjg.js} +4 -4
  9. package/dist/assets/{Permissions-Be6cIkPg.js → Permissions-BovobeZw.js} +3 -3
  10. package/dist/assets/Plugins-DvOf_B62.js +2 -0
  11. package/dist/assets/ProvenanceBadge-Dutz_4OY.js +1 -0
  12. package/dist/assets/{SaveBar-xQZ2EBOn.js → SaveBar-CT5u6ZCJ.js} +1 -1
  13. package/dist/assets/Scheduler-B7GSnZj5.js +16 -0
  14. package/dist/assets/{ScopeSwitcher-BAfquN6Y.js → ScopeSwitcher-BUYDpz2v.js} +1 -1
  15. package/dist/assets/Settings-DIRmr3tL.js +3 -0
  16. package/dist/assets/{SkillReferenceGraph-BI1YtCbB.js → SkillReferenceGraph-CdGr6d3_.js} +1 -1
  17. package/dist/assets/Skills-BQOheQv4.js +3 -0
  18. package/dist/assets/SystemPrompt-5LsimKbX.js +1 -0
  19. package/dist/assets/TagLibrary-DreLsT3n.js +1 -0
  20. package/dist/assets/{TiptapBody-BptXAVR9.js → TiptapBody-C9kmlBnI.js} +1 -1
  21. package/dist/assets/{Toggle-BwiClCSI.js → Toggle-BKLCBu9A.js} +1 -1
  22. package/dist/assets/{index-D3P_jldk.css → index-CKH5Uxik.css} +1 -1
  23. package/dist/assets/index-Db_SK9rW.js +3079 -0
  24. package/dist/assets/settingsSchema-B5jBhSUP.js +1 -0
  25. package/dist/index.html +2 -2
  26. package/package.json +1 -1
  27. package/src/main/__tests__/agentEffortResolve.test.cjs +117 -0
  28. package/src/main/__tests__/agentLibrary.test.cjs +21 -0
  29. package/src/main/__tests__/agentModelResolve.test.cjs +16 -0
  30. package/src/main/__tests__/agentOverlayWrite.test.cjs +95 -0
  31. package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +44 -0
  32. package/src/main/__tests__/personaMerge.test.cjs +169 -0
  33. package/src/main/__tests__/prdCreatePlanId.test.cjs +132 -0
  34. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +13 -0
  35. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +75 -10
  36. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +47 -2
  37. package/src/main/agentLibrary.cjs +86 -40
  38. package/src/main/build-info.json +4 -4
  39. package/src/main/chatRunner.cjs +5 -0
  40. package/src/main/index.cjs +10 -0
  41. package/src/main/ipcSchemas.cjs +12 -0
  42. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +10 -5
  43. package/src/main/lib/__tests__/modelCatalog.test.cjs +202 -0
  44. package/src/main/lib/agentEffortResolve.cjs +74 -0
  45. package/src/main/lib/agentModelResolve.cjs +52 -59
  46. package/src/main/lib/agentPersonaSchema.cjs +3 -0
  47. package/src/main/lib/effectiveModelInfo.cjs +38 -20
  48. package/src/main/lib/epicMint.cjs +5 -2
  49. package/src/main/lib/epicWorktreeMerge.cjs +7 -6
  50. package/src/main/lib/modelCatalog.cjs +243 -0
  51. package/src/main/lib/personaMerge.cjs +166 -0
  52. package/src/main/lib/prdCreate.cjs +23 -5
  53. package/src/main/lib/prdDisposition.cjs +46 -0
  54. package/src/main/lib/prdFrontmatter.cjs +6 -2
  55. package/src/main/lib/promptSessionSchema.cjs +3 -0
  56. package/src/main/lib/promptSessionsCreateEpic.cjs +5 -3
  57. package/src/main/pty.cjs +16 -2
  58. package/src/main/scheduler/prdParser.cjs +2 -0
  59. package/src/main/scheduler.cjs +21 -5
  60. package/src/main/templates/PRD_AUTHORING.md +4 -0
  61. package/src/preload/api.d.ts +53 -2
  62. package/src/preload/index.cjs +4 -0
  63. package/dist/assets/AgentLibrary-Bu-1eT_n.js +0 -3
  64. package/dist/assets/DataModel-Bk9rkJ8x.js +0 -1
  65. package/dist/assets/ListDetail-D4bxU_-2.js +0 -1
  66. package/dist/assets/Panel-RMz3Acpu.js +0 -1
  67. package/dist/assets/Plugins-B8sTWf2K.js +0 -2
  68. package/dist/assets/ProvenanceBadge-CO-DZN38.js +0 -1
  69. package/dist/assets/Scheduler-CF3zsJBw.js +0 -16
  70. package/dist/assets/Settings-uPjmqutA.js +0 -3
  71. package/dist/assets/Skills-BEy9FDYd.js +0 -3
  72. package/dist/assets/SystemPrompt-BYkkw-LL.js +0 -1
  73. package/dist/assets/TagLibrary-Kg3yOC5b.js +0 -1
  74. package/dist/assets/index-a2MVk8qh.js +0 -3074
  75. package/dist/assets/settingsSchema-DgxlStF5.js +0 -3
package/src/main/pty.cjs CHANGED
@@ -23,6 +23,7 @@ const { checkInsideHome } = require('./lib/insideHome.cjs');
23
23
  const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
24
24
  const opsErrorLog = require('./lib/opsErrorLog.cjs');
25
25
  const { planEpicSpawn } = require('./lib/epicSpawnPlan.cjs');
26
+ const { resolveEpicSpawnCwd } = require('./lib/epicSpawnCwd.cjs');
26
27
  const telemetryCounters = require('./lib/telemetryCounters.cjs');
27
28
 
28
29
  // Absolute path to the installed package root (src/main/ -> ../../), shown in
@@ -180,8 +181,22 @@ class PtyManager {
180
181
  // so this asks the same decision function chatRunner.cjs does (epicSpawnPlan.cjs). `cwd`
181
182
  // itself is NEVER repointed; only this actual PTY spawn option is (epicSpawnCwd.cjs's
182
183
  // ops-root hazard). A refused plan is surfaced in-tab rather than spawning into a bad cwd.
184
+ // Split: Chat and Terminal share this one verdict function, but the Terminal additionally
185
+ // downgrades `epic_closed` to a plain shell — it opens `$SHELL -il` (no --resume, no
186
+ // transcript write), not a chat turn. That path uses the read-side resolver WITHOUT
187
+ // `deps.restore`, so opening a closed Epic's terminal never re-attaches a checkout.
183
188
  const plan = planEpicSpawn({ cwd, claudeSessionId: tabId });
184
- if (!plan.ok) {
189
+ let spawnCwd;
190
+ if (plan.ok) {
191
+ spawnCwd = plan.execCwd;
192
+ } else if (plan.code === 'epic_closed') {
193
+ spawnCwd = resolveEpicSpawnCwd({ cwd, claudeSessionId: tabId });
194
+ sendIfAlive(
195
+ this.window,
196
+ `pty:data:${tabId}`,
197
+ `\r\nThis Epic is completed \u2014 opening a read-only shell in ${spawnCwd}. Start a new Epic for new work.\r\n`,
198
+ );
199
+ } else {
185
200
  opsErrorLog.appendError({
186
201
  cwd,
187
202
  scope: 'pty',
@@ -193,7 +208,6 @@ class PtyManager {
193
208
  setImmediate(() => sendIfAlive(this.window, `pty:exit:${tabId}`, { exitCode: 1, signal: undefined }));
194
209
  return { pid: null, cwd, reattached: false, error: plan.message };
195
210
  }
196
- const spawnCwd = plan.execCwd;
197
211
  if (spawnCwd !== cwd) {
198
212
  console.log(`[pty] tabId=${tabId} isolated in worktree ${spawnCwd}`);
199
213
  }
@@ -126,6 +126,8 @@ async function parsePrdRaw(filePath) {
126
126
  // the decision (first-ever PRD in its Epic, or one with its own explicit
127
127
  // dependsOn).
128
128
  disposition: (fm.disposition === 'append' || fm.disposition === 'new-head') ? fm.disposition : null,
129
+ // Durable wave identity (createPrd-stamped); malformed values read as absent.
130
+ planId: (typeof fm.planId === 'string' && /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(fm.planId)) ? fm.planId : null,
129
131
  // Opt-in exclusive-lease flag (PRD 1107, quietMachineLease.cjs +
130
132
  // schedulerBatch.cjs's pickNextBatch). Only a literal `true` opts in —
131
133
  // matches prdFrontmatter.cjs's applyKey semantics for this field.
@@ -145,6 +145,7 @@ const queueOps = require('./queueOps.cjs');
145
145
  const { resolvePrdsDirs, resolveArchivedPrdsDirs, resolvePrdWriteDir, listEpicPrdDirs, listArchivedPrdDirs, deriveProjectCwdFromPrdPath } = require('./lib/prdLocations.cjs');
146
146
  const { ensureEpic, appendPrdCreatedEvent, readActiveIndex } = require('./lib/epicMint.cjs');
147
147
  const agentModelResolve = require('./lib/agentModelResolve.cjs');
148
+ const { resolveEpicEffort, effortArgs } = require('./lib/agentEffortResolve.cjs');
148
149
  const { transitionJob, STATUS_HISTORY_CAP, LEGAL_TRANSITIONS } = require('./lib/scheduleJobTransitions.cjs');
149
150
  const { buildContextDigest, composeExecutorPrompt } = require('./lib/epicContextDigest.cjs');
150
151
  const { JOB_STATUSES } = require('./lib/scheduleJobSchema.cjs');
@@ -181,7 +182,7 @@ const supervisorRecord = require('./lib/jobSupervisorRecord.cjs');
181
182
  const adoptedRunSupervisor = require('./lib/adoptedRunSupervisor.cjs');
182
183
  const { splitFrontmatter, parsePrdFile, serializePrdFile } = require('./lib/prdFrontmatter.cjs');
183
184
  const { resolveDepSlug, findNearMatches } = require('./lib/depSlugResolve.cjs');
184
- const { computeDispositionRewrite } = require('./lib/prdDisposition.cjs');
185
+ const { computeDispositionRewrite, mintPlanId, resolveInheritedPlanId } = require('./lib/prdDisposition.cjs');
185
186
  const { migratePrds, consolidateFlatPrds, legacyAdoptExistingPrds } = require('./lib/prdMigration.cjs');
186
187
  const { allProjectCwds } = require('./lib/activeSessions.cjs');
187
188
 
@@ -2811,6 +2812,7 @@ async function reconcile(state) {
2811
2812
  epicId: p.epicId ?? job.epicId ?? null,
2812
2813
  dependsOn: p.dependsOn,
2813
2814
  disposition: p.disposition ?? null,
2815
+ planId: p.planId ?? null,
2814
2816
  quietMachine: p.quietMachine === true,
2815
2817
  budgetExempt: p.budgetExempt === true,
2816
2818
  originSessionId: job.originSessionId
@@ -2933,6 +2935,7 @@ async function reconcile(state) {
2933
2935
  epicId: p.epicId ?? inv.row?.epicId ?? null,
2934
2936
  dependsOn: p.dependsOn,
2935
2937
  disposition: p.disposition ?? null,
2938
+ planId: p.planId ?? null,
2936
2939
  quietMachine: p.quietMachine === true,
2937
2940
  budgetExempt: p.budgetExempt === true,
2938
2941
  originSessionId: inv.row?.originSessionId ?? resolveOriginSessionId(repairedCwd, p.epicId ?? p.sourcePromptId),
@@ -3067,6 +3070,7 @@ async function reconcile(state) {
3067
3070
  epicId: p.epicId ?? null,
3068
3071
  dependsOn: p.dependsOn,
3069
3072
  disposition: p.disposition ?? null,
3073
+ planId: p.planId ?? null,
3070
3074
  quietMachine: p.quietMachine === true,
3071
3075
  budgetExempt: p.budgetExempt === true,
3072
3076
  originSessionId: resolveOriginSessionId(discoveredCwd, p.epicId ?? p.sourcePromptId),
@@ -5249,15 +5253,17 @@ async function performLeftoverQuarantine(job, paths, headBefore = null) {
5249
5253
  * selects `--resume <sessionId>` (reconnect) INSTEAD of `--session-id
5250
5254
  * <sessionId>` (mint) — the two flags are mutually exclusive, never both.
5251
5255
  * `--model` is always explicit (never left to the CLI's drifting default —
5252
- * see conventions.md). `systemPrompt`, when given (the PRD's `agentType`
5256
+ * see conventions.md). `effort`, when a level (persona `effort:` via
5257
+ * agentEffortResolve.cjs), appends `--effort <level>`; null/inherit → no flag. `systemPrompt`, when given (the PRD's `agentType`
5253
5258
  * persona body, resolved by agentModelResolve.cjs's resolvePrdPersonaForSpawn),
5254
5259
  * is passed as `--append-system-prompt` so the executor IS that persona at
5255
5260
  * launch rather than being asked in prose to adopt one.
5256
5261
  */
5257
- function buildClaudeSpawnArgs({ prompt, model, sessionId, resume, systemPrompt }) {
5262
+ function buildClaudeSpawnArgs({ prompt, model, effort, sessionId, resume, systemPrompt }) {
5258
5263
  return [
5259
5264
  '-p', prompt,
5260
5265
  '--model', model,
5266
+ ...effortArgs(effort),
5261
5267
  ...(systemPrompt ? ['--append-system-prompt', systemPrompt] : []),
5262
5268
  '--dangerously-skip-permissions',
5263
5269
  '--output-format', 'stream-json',
@@ -5510,7 +5516,8 @@ async function executeJob(job, runDir, defaultCwd, onPid, execCwd, resumeTarget
5510
5516
  // a dangling/absent agentType falls back to no persona + FALLBACK_MODEL
5511
5517
  // and is logged once by resolvePrdPersonaForSpawn itself.
5512
5518
  const personaResolution = await agentModelResolve.resolvePrdPersonaForSpawn({ cwd, agentType: job.agentType });
5513
- safeLog(`[scheduler] agentType=${job.agentType || '(none)'} persona=${personaResolution.personaPath || '(fallback — no persona applied)'} model=${personaResolution.model}\n`);
5519
+ const personaEffort = resolveEpicEffort({ cwd, agentType: job.agentType }).effort;
5520
+ safeLog(`[scheduler] agentType=${job.agentType || '(none)'} persona=${personaResolution.personaPath || '(fallback — no persona applied)'} model=${personaResolution.model}${personaEffort ? ` effort=${personaEffort}` : ''}\n`);
5514
5521
 
5515
5522
  return await new Promise((resolve) => {
5516
5523
  const claudeBin = resolveClaudeBin();
@@ -5710,6 +5717,7 @@ async function executeJob(job, runDir, defaultCwd, onPid, execCwd, resumeTarget
5710
5717
  args: buildClaudeSpawnArgs({
5711
5718
  prompt,
5712
5719
  model: personaResolution.model,
5720
+ effort: personaEffort,
5713
5721
  sessionId,
5714
5722
  resume: !!resumeTarget,
5715
5723
  systemPrompt: personaResolution.systemPrompt,
@@ -11946,6 +11954,7 @@ async function listPrdsInternal() {
11946
11954
  dependsOn: parsed.dependsOn ?? null,
11947
11955
  agentType: parsed.agentType ?? null,
11948
11956
  disposition: parsed.disposition ?? null,
11957
+ planId: parsed.planId ?? null,
11949
11958
  mtimeMs: stat.mtimeMs,
11950
11959
  archived,
11951
11960
  };
@@ -12379,7 +12388,14 @@ const remote = {
12379
12388
  const rows = listing.prds ?? [];
12380
12389
  const rewrite = computeDispositionRewrite({ slug, disposition, dependsOn: dependsOn ?? [], rows });
12381
12390
  if (!rewrite.ok) return rewrite;
12382
- return this.updatePrd({ slug, cwd, frontmatter: { dependsOn: rewrite.dependsOn, disposition } });
12391
+ // Keep the durable planId in step with the new relationship: a promoted head
12392
+ // starts its own plan; a re-attached row joins the target chain's plan (cleared
12393
+ // when the target predates the stamp, so the derivation fallback applies).
12394
+ let planId = mintPlanId();
12395
+ if (disposition === 'append') {
12396
+ planId = resolveInheritedPlanId(rewrite.dependsOn, rows).planId;
12397
+ }
12398
+ return this.updatePrd({ slug, cwd, frontmatter: { dependsOn: rewrite.dependsOn, disposition, planId } });
12383
12399
  },
12384
12400
 
12385
12401
  // Cancels a job that hasn't finished yet. A 'running' job's process group
@@ -141,6 +141,10 @@ estimateMinutes: 60
141
141
  - `estimateMinutes` is used for ETA display; include a realistic estimate (note: empirical median is ~10 min, p90 ~20 min — avoid wildly inflated estimates that hide real outliers).
142
142
  - `parallelGroup` in frontmatter, when present, IS honored by the scheduler (`pickNextBatch` reads `parallelGroup ?? 99` and overrides the filename NN). Use this only for cross-stream interleaving — e.g., the cellar series `122-`, `123-`, `124-` overrides to groups `113`, `114`, `115` so cellar steps fire alongside the parallel etch steps. Do NOT use it to reorder within a single stream; rename the file instead.
143
143
 
144
+ ### `planId` (API-owned — never pass it)
145
+
146
+ `planId` is a frontmatter key that `createPrd` stamps on every PRD: the durable identity of the plan (wave) the PRD belongs to. An `append` PRD (or one with an explicit `dependsOn`) inherits the planId of the PRD(s) it attaches behind; a first-ever or `new-head` PRD mints a fresh one. The Scheduler tracker groups by it, so a second plan in one Epic is a recorded fact, not a re-derivation. Callers never pass or hand-write it — `scheduler_create_prd` ignores it. PRDs without one (pre-stamp) fall back to dependency-graph grouping.
147
+
144
148
  ### Artifact-only PRDs
145
149
 
146
150
  Use `deliverable: artifact` + `artifactPaths: [a, b]` (both passed to `scheduler_create_prd`) ONLY when every deliverable is a file the target repo deliberately git-excludes (e.g. patches/notes under `session-manager-operations/review-records/`, matched by `.git/info/exclude`), so "no commit" is the correct outcome.
@@ -235,6 +235,8 @@ export interface AgentPersona {
235
235
  description: string | null;
236
236
  tools: string[];
237
237
  model: string | null;
238
+ /** Per-Epic reasoning effort (`effort:` frontmatter; a `models.catalog` effort level). Null = inherit. Passed to the claude spawn as `--effort` (never `auto`). */
239
+ effort: string | null;
238
240
  color: string | null;
239
241
  /** Epic intent tags (tagLibrary.ts's TAG_LIBRARY) this persona is associated with. */
240
242
  tags: AgentPersonaTag[];
@@ -253,6 +255,8 @@ export interface AgentPersona {
253
255
  body: string;
254
256
  /** Project names (basename of cwd) whose currently-open tab overlays this agent. */
255
257
  overridingProjects: string[];
258
+ /** Per open project with an overlay: which frontmatter keys / body the overlay overrides (merged view provenance). */
259
+ overrideDetails?: { project: string; fields: string[]; values?: Record<string, string>; bodyOverridden: boolean; issue: string | null }[];
256
260
  }
257
261
 
258
262
  /** Payload for `agents.savePersona` — creates or overwrites a global persona file. */
@@ -263,6 +267,8 @@ export interface AgentPersonaSaveInput {
263
267
  description: string;
264
268
  tools: string[];
265
269
  model: string;
270
+ /** Effort level, or `'inherit'`/omitted to write no `effort:` line. */
271
+ effort?: string;
266
272
  color: string;
267
273
  tags: AgentPersonaTag[];
268
274
  /** Project cwds (or the `'*'` sentinel) this persona's Action button appears in. */
@@ -272,6 +278,8 @@ export interface AgentPersonaSaveInput {
272
278
  /** Caption override for this persona's Action button. */
273
279
  actionLabel?: string;
274
280
  title?: string;
281
+ /** Open project name: write that project's frontmatter-only override (only `model`/`effort` are used) instead of the global file. */
282
+ projectName?: string;
275
283
  body: string;
276
284
  }
277
285
 
@@ -556,6 +564,8 @@ export interface ScheduleJob {
556
564
  * independent root). Refreshed from the PRD file on every reconcile, like
557
565
  * dependsOn above; null when this row never needed the decision. */
558
566
  disposition?: 'append' | 'new-head' | null;
567
+ /** Durable wave identity stamped into PRD frontmatter by createPrd(); buildPlans groups by it. Null on PRDs that predate the stamp. */
568
+ planId?: string | null;
559
569
  /** The originating claude session — the Epic's claudeSessionId, resolved
560
570
  * from active-index.json at ingest (PRD 832). An Epic IS a tagged session. */
561
571
  originSessionId?: string | null;
@@ -575,6 +585,9 @@ export interface ScheduleJob {
575
585
  * intent-carrying `sourcePromptId`/`sourceTabId`, which can disagree.
576
586
  * Authoritative source for "which Epic is this from" in every UI. */
577
587
  epicId?: string | null;
588
+ /** Renderer-only: true for a row synthesized from an archived PRD file (no queue row
589
+ * exists to act on) — see lib/archivedPlanRows. Never present in queue.json. */
590
+ synthetic?: boolean;
578
591
  /** Bounded trail of accepted status transitions (scheduleJobTransitions.cjs's
579
592
  * transitionJob), oldest-first, capped at ~20 entries. Lets a status
580
593
  * change be reviewed after the fact instead of only inferred from a
@@ -703,6 +716,8 @@ export interface PrdListItem {
703
716
  dependsOn?: string[] | null;
704
717
  /** PRD frontmatter `disposition` — see ScheduleJob.disposition. */
705
718
  disposition?: 'append' | 'new-head' | null;
719
+ /** PRD frontmatter `planId` — see ScheduleJob.planId. */
720
+ planId?: string | null;
706
721
  /** True when this PRD's source .md was found in a `prds-archived/` dir
707
722
  * (its scheduler job already ran to completion) rather than the live
708
723
  * `prds/` dir. Archived PRDs have no matching queue.json job row (the
@@ -1637,7 +1652,7 @@ export interface SessionManagerAPI {
1637
1652
  * resolved with project-overlay-then-global precedence for `cwd` — unlike
1638
1653
  * `listPersonas` above, which only reads the global directory. Null when neither
1639
1654
  * location has the file. */
1640
- getPersonaBody: (payload: { cwd: string; name: string }) => Promise<{ path: string; text: string } | null>;
1655
+ getPersonaBody: (payload: { cwd: string; name: string }) => Promise<{ path: string; text: string; provenance?: Record<string, 'overlay' | 'global'>; bodySource?: 'overlay' | 'global' } | null>;
1641
1656
  /** "What will this Epic actually run as?" — persona alias, overlay-aware
1642
1657
  * provenance, and evidence-based concrete model id (scheduler run log or
1643
1658
  * session transcript). Never throws on the main side; a dangling
@@ -1649,9 +1664,15 @@ export interface SessionManagerAPI {
1649
1664
  agentType: string;
1650
1665
  modelAlias: string | null;
1651
1666
  modelSource: 'persona' | 'persona-overlay' | 'inherit' | 'fallback';
1667
+ /** Per-frontmatter-key origin of the merged persona (overlay vs global). */
1668
+ personaProvenance?: Record<string, 'overlay' | 'global'>;
1652
1669
  resolvedModelId: string | null;
1653
1670
  resolvedFrom: 'scheduler-run' | 'transcript' | null;
1654
- effortReachable: boolean;
1671
+ /** Env-var path only: would cleanChildEnv strip CLAUDE_EFFORT. Persona effort travels on argv regardless. */
1672
+ effortEnvReachable: boolean;
1673
+ /** Persona `effort:` level (null = pass no --effort) and where it came from. */
1674
+ personaEffort: string | null;
1675
+ personaEffortSource: 'persona' | 'persona-overlay' | 'inherit' | null;
1655
1676
  }>;
1656
1677
  /** The launch-time authority for an Epic-backed session's `--model`: the SAME
1657
1678
  * resolver (`agentModelResolve.cjs`'s `resolveEpicModel`) chatRunner.cjs's Chat
@@ -1660,9 +1681,36 @@ export interface SessionManagerAPI {
1660
1681
  * (project `.claude/agents/<name>.md` wins over global), never throws — a
1661
1682
  * dangling agentType or absent/`inherit` model falls back to `'sonnet'`. */
1662
1683
  resolveEpicModel: (payload: { cwd: string; claudeSessionId: string }) => Promise<string>;
1684
+ /** Effort twin of `resolveEpicModel` (`agentEffortResolve.cjs`): the persona `effort:` level
1685
+ * Terminal must launch with, or `effort: null` = append NO `--effort` flag (inherit / absent /
1686
+ * dangling persona). Chat resolves the same value in-process. Never throws. */
1687
+ resolveEpicEffort: (payload: { cwd: string; claudeSessionId: string }) => Promise<{
1688
+ effort: string | null;
1689
+ source: 'persona' | 'persona-overlay' | 'inherit' | null;
1690
+ }>;
1663
1691
  /** Fires after any save/delete/removeOverride — subscribers should re-fetch listPersonas(). */
1664
1692
  onChanged: (handler: () => void) => () => void;
1665
1693
  };
1694
+ models: {
1695
+ /** Live model/effort catalog (`modelCatalog.cjs`'s `resolveModelCatalog`). Never rejects from
1696
+ * the resolver itself — a failed probe degrades down cache → floor and sets `degraded`.
1697
+ * `cwd` only affects `availableModels` (settings-scope allowlist); `force` bypasses the cache. */
1698
+ catalog: (payload: { cwd?: string; force?: boolean }) => Promise<{
1699
+ aliases: string[];
1700
+ models: string[];
1701
+ effortLevels: string[];
1702
+ settingsEffortLevels: string[];
1703
+ availableModels: string[] | null;
1704
+ claudeVersion: string | null;
1705
+ probedAt: string | null;
1706
+ sources: {
1707
+ aliases: 'probe' | 'cache' | 'floor';
1708
+ models: 'binary' | 'cache' | 'floor';
1709
+ effortLevels: 'probe' | 'cache' | 'floor';
1710
+ };
1711
+ degraded: boolean;
1712
+ }>;
1713
+ };
1666
1714
  logs: {
1667
1715
  write: (
1668
1716
  scope: string,
@@ -2053,6 +2101,9 @@ export interface PromptSessionsCreateEpicPayload {
2053
2101
  goalText: string;
2054
2102
  tag?: 'feature' | 'bug' | 'discussion' | 'build' | 'project-home-builder' | 'bilko-host-publisher';
2055
2103
  agentType?: string;
2104
+ /** Per-Epic model/effort overrides (New Session card); omitted = the persona's own. */
2105
+ model?: string;
2106
+ effort?: string;
2056
2107
  source?: {
2057
2108
  producer: 'new-epic-ui' | 'scheduler-dispatch';
2058
2109
  prdSlug?: string;
@@ -108,6 +108,7 @@ contextBridge.exposeInMainWorld('api', {
108
108
  getPersonaBody: (payload) => ipcRenderer.invoke('agents:get-persona-body', payload),
109
109
  resolveModelInfo: (payload) => ipcRenderer.invoke('agents:resolve-model-info', payload),
110
110
  resolveEpicModel: (payload) => ipcRenderer.invoke('agents:resolve-epic-model', payload),
111
+ resolveEpicEffort: (payload) => ipcRenderer.invoke('agents:resolve-epic-effort', payload),
111
112
  // Fired after any save/delete/removeOverride so every mounted
112
113
  // subscriber (Agent Library, Tag Library) re-fetches the same file.
113
114
  onChanged: (handler) => {
@@ -116,6 +117,9 @@ contextBridge.exposeInMainWorld('api', {
116
117
  return () => ipcRenderer.removeListener('agents:changed', listener);
117
118
  },
118
119
  },
120
+ models: {
121
+ catalog: (payload) => ipcRenderer.invoke('models:catalog', payload),
122
+ },
119
123
  logs: {
120
124
  // ctx is optional: { cwd, tabId, epicId, tags } — when present and
121
125
  // level is 'error', main also appends a tagged line to that project's
@@ -1,3 +0,0 @@
1
- import{ah as e,U as V,au as h,l as B,b as P,aH as w,aE as X,T as _,aG as Z,aO as ee,A as T}from"./index-a2MVk8qh.js";import{P as te}from"./Panel-RMz3Acpu.js";import{L as ne}from"./ListDetail-D4bxU_-2.js";import"./monaco-editor-BW5C4Iv1.js";function y({children:t,onClick:r,disabled:g,variant:f="default",tooltip:l,type:m="button",className:c}){const u=`px-2 py-0.5 text-xs rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed ${f==="primary"?"text-accent border-accent/50 hover:bg-bg-hi":f==="danger"?"text-red-400 hover:text-red-300 border-line hover:border-red-400/50":"text-fg-dim border-line hover:text-fg hover:bg-bg-hi"} ${c??""}`,a=e.jsx("button",{type:m,title:l,onClick:r,disabled:g,className:u,children:t});return l?e.jsx(V,{content:l,align:"bottom-center",children:a}):a}const ae=["inherit","haiku","sonnet","opus","fable"],G=["Read","Grep","Glob","Bash","Write","Edit","WebFetch","WebSearch","Task"],se=["","red","orange","yellow","green","cyan","blue","purple","pink"],K={red:"#c0392b",orange:"#b85c34",yellow:"#c9a227",green:"#6f7d52",cyan:"#3f8f8a",blue:"#4a6fa5",purple:"#7a6a8a",pink:"#b45a80"};function E(t){return{name:t.name,description:t.description??"",tools:t.tools,model:t.model??"inherit",color:t.color??"",tags:t.tags,projects:t.projects??[],action:t.action??"",actionLabel:t.actionLabel??"",body:t.body}}const I={name:"new-agent",description:"",tools:["Read","Grep"],model:"inherit",color:"",tags:[],projects:[],action:"",actionLabel:"",body:""},re=new Set(_.map(t=>t.tag));function oe(t){return t.filter(r=>re.has(r))}function ie(){const[t,r]=h.useState(null),[g,f]=h.useState(null),[l,m]=h.useState(""),[c,i]=h.useState(null),[u,a]=h.useState(!1),[v,N]=h.useState(!1),[D,C]=h.useState(null),[k,s]=h.useState(!1),j=h.useRef(!0);h.useEffect(()=>()=>{j.current=!1},[]);const p=async n=>{try{const x=await window.api.agents.listPersonas();if(!j.current)return;r(x),f(L=>{var O;return n??L??((O=x[0])==null?void 0:O.name)??null})}catch(x){if(!j.current)return;r([]),w.error(x.message||"failed to load agent personas")}};if(h.useEffect(()=>{p()},[]),h.useEffect(()=>window.api.agents.onChanged(()=>p()),[]),h.useEffect(()=>{const n=X();n&&f(n);const x=L=>f(L.detail);return window.addEventListener("sm:select-persona",x),()=>window.removeEventListener("sm:select-persona",x)},[]),t===null)return e.jsx(B,{title:"loading…"});const $=l.toLowerCase(),R=t.filter(n=>!$||n.name.toLowerCase().includes($)||(n.description??"").toLowerCase().includes($)),d=t.find(n=>n.name===g)??t[0]??null,o=c??(d?E(d):null),F=!!c&&!!d&&JSON.stringify(c)!==JSON.stringify(E(d)),S=u,W=n=>{i(null),a(!1),N(!1),C(null),f(n)},z=n=>i(x=>({...x??(d?E(d):I),...n})),M=()=>{i({...I}),a(!0),N(!1)},J=()=>{o&&(i({...o,name:o.name+"-copy"}),a(!0))},H=()=>{i(null),a(!1)},U=async()=>{if(o){if(!/^[a-z][a-z0-9-]*$/.test(o.name)){w.error('agent name must be lowercase, hyphenated (e.g. "my-agent")');return}s(!0);try{const n={name:o.name,originalName:S||d==null?void 0:d.name,description:o.description,tools:o.tools,model:o.model,color:o.color,tags:oe(o.tags),projects:o.projects,action:o.action,actionLabel:o.actionLabel,body:o.body};await window.api.agents.savePersona(n),w.info(S?`created ${o.name}`:`saved ${o.name}`),i(null),a(!1),await p(o.name)}catch(n){w.error(n.message||"failed to save agent persona")}finally{s(!1)}}},Y=async()=>{if(d){s(!0);try{await window.api.agents.deletePersona({name:d.name}),w.info(`deleted ${d.name}`),N(!1),i(null),a(!1),await p()}catch(n){w.error(n.message||"failed to delete agent persona")}finally{s(!1)}}},q=async n=>{s(!0);try{await window.api.agents.deletePersona({name:n}),w.info(`deleted ${n}`),C(null),g===n&&(i(null),a(!1)),await p()}catch(x){w.error(x.message||"failed to delete agent persona")}finally{s(!1)}},Q=async n=>{if(d)try{await window.api.agents.removeOverride({name:d.name,projectName:n}),w.info(`removed ${n}'s override of ${d.name}`),await p(d.name)}catch(x){w.error(x.message||"failed to remove override")}};return e.jsx(te,{toolbar:e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"text-fg-faint",children:[t.length," persona",t.length===1?"":"s"]}),e.jsx("input",{value:l,onChange:n=>m(n.target.value),placeholder:"filter…",className:"bg-bg border border-line rounded px-2 py-0.5 text-xs text-fg w-40"}),e.jsx("div",{className:"flex-1"}),e.jsx(y,{variant:"primary",onClick:M,children:"+ New agent"})]}),children:e.jsx(ne,{sidebar:e.jsxs("div",{className:"py-1",children:[S&&e.jsx("div",{className:"w-full text-left px-3 py-1 text-xs flex flex-col gap-0.5 bg-bg-hi text-fg border-l-2 border-accent",children:e.jsxs("span",{className:"flex items-center gap-2 justify-between w-full",children:[e.jsx("span",{className:"truncate font-mono",children:o==null?void 0:o.name}),e.jsx("span",{className:"shrink-0 text-[10px] font-semibold text-accent",children:"new"})]})}),R.length===0&&!S?e.jsx("div",{className:"px-3 py-1 text-xs text-fg-faint italic",children:"no agent personas found"}):R.map(n=>{const x=!S&&n.name===g,L=x&&F,O=D===n.name;return e.jsxs("div",{"data-agent-row":n.name,className:`group w-full text-left px-3 py-1 text-xs flex flex-col gap-0.5 border-l-2 cursor-pointer ${x?"bg-bg-hi text-fg border-accent":"text-fg-dim hover:text-fg hover:bg-bg-hi border-transparent"}`,onClick:()=>W(n.name),children:[e.jsxs("span",{className:"flex items-center gap-2 justify-between w-full",children:[e.jsxs("span",{className:"flex items-center gap-1.5 min-w-0",children:[e.jsx("span",{className:"w-2 h-2 rounded-sm shrink-0",style:{background:n.color?K[n.color]??n.color:"var(--fg-faint, #999)",opacity:n.color?1:.35}}),e.jsx("span",{className:"truncate font-mono",children:n.name})]}),e.jsxs("span",{className:"shrink-0 flex items-center gap-1.5",children:[L&&e.jsx("span",{className:"text-[10px] font-semibold text-accent",children:"unsaved"}),!L&&n.overridingProjects.length>0&&e.jsxs(P,{tone:"dim",children:[n.overridingProjects.length," override",n.overridingProjects.length>1?"s":""]}),O?e.jsxs("span",{className:"flex items-center gap-1",onClick:A=>A.stopPropagation(),children:[e.jsx("button",{onClick:()=>q(n.name),disabled:k,title:`Delete ${n.name}`,className:"text-[10px] font-semibold text-red-400 hover:text-red-300",children:"confirm"}),e.jsx("button",{onClick:()=>C(null),title:"Cancel",className:"text-[10px] text-fg-faint hover:text-fg",children:"cancel"})]}):e.jsx("button",{onClick:A=>{A.stopPropagation(),C(n.name)},title:`Delete ${n.name}`,className:"opacity-0 group-hover:opacity-100 text-fg-faint hover:text-red-400 transition-opacity",children:"×"})]})]}),n.description&&e.jsx("span",{className:"truncate text-fg-faint",children:n.description})]},n.name)})]}),detail:o?e.jsx(le,{obj:o,set:z,saved:d,dirty:F,isNew:S,busy:k,confirmDelete:v,setConfirmDelete:N,onDuplicate:J,onRevert:H,onSave:U,onDelete:Y,onDropOverride:Q}):e.jsx(B,{title:"select an agent"})})})}const he=h.memo(ie);function le({obj:t,set:r,saved:g,dirty:f,isNew:l,busy:m,confirmDelete:c,setConfirmDelete:i,onDuplicate:u,onRevert:a,onSave:v,onDelete:N,onDropOverride:D}){const C=`~/.claude/agents/${t.name}.md`,k=f||l;return e.jsxs("div",{className:"max-w-3xl",children:[e.jsxs("div",{className:"px-4 py-3 border-b border-line flex items-center gap-2 flex-wrap",children:[e.jsx("span",{className:"text-sm font-semibold text-fg font-mono",children:t.name}),l?e.jsx(P,{tone:"accent",children:"unsaved draft"}):f?e.jsx(P,{tone:"warn",children:"edited"}):e.jsx(P,{tone:"good",children:"saved"}),e.jsx("span",{className:"ml-auto text-[11px] text-fg-faint font-mono",children:C})]}),e.jsxs("div",{className:"p-4 space-y-4",children:[e.jsx(b,{label:"name",hint:"Filename on disk — lowercase, hyphenated.",children:e.jsx("input",{value:t.name,onChange:s=>r({name:s.target.value.toLowerCase()}),className:"w-full bg-bg border border-line rounded px-2 py-1 text-xs text-fg font-mono"})}),e.jsx(b,{label:"description",hint:"Shown in the list and in agent pickers.",children:e.jsx("input",{value:t.description,onChange:s=>r({description:s.target.value}),className:"w-full bg-bg border border-line rounded px-2 py-1 text-xs text-fg"})}),e.jsx(b,{label:"default model",hint:"This persona's default model for its Epics — sets the --model an Epic launches with (Terminal + Chat both honor it). 'inherit' falls back to each view's own default, not this Settings page. Cheap models for read-only personas; opus for judgement calls.",children:e.jsx(de,{options:ae,value:t.model,onChange:s=>r({model:s}),mono:!0})}),e.jsx(b,{label:"tools",hint:`${t.tools.length} of ${G.length} granted. Anything not ticked is refused at call time.`,children:e.jsx("div",{className:"flex flex-wrap gap-1.5",children:G.map(s=>{const j=t.tools.includes(s);return e.jsx("button",{onClick:()=>r({tools:j?t.tools.filter(p=>p!==s):[...t.tools,s]}),className:`px-2 py-0.5 rounded-full text-[11px] font-mono border ${j?"bg-sage/15 text-sage-dark border-sage/30":"bg-bg-hi text-fg-faint border-line"}`,children:s},s)})})}),e.jsx(b,{label:"color",children:e.jsx("div",{className:"flex gap-1.5",children:se.map(s=>e.jsx("button",{title:s||"none",onClick:()=>r({color:s}),className:"w-5 h-5 rounded",style:{background:s?K[s]:"transparent",border:t.color===s?"2px solid var(--accent, #b85c34)":"1px solid var(--line, #555)"}},s||"none"))})}),e.jsx(b,{label:"tags",hint:"Session mission tags this persona is associated with — shown as the default agent on that tag's own page. The first one (in Tag Library order) is the MISSION an Action button's session opens with.",children:e.jsx("div",{className:"flex flex-wrap gap-1.5",children:_.map(s=>{const j=t.tags.includes(s.tag),p=Z(s.tag);return e.jsxs("button",{onClick:()=>r({tags:j?t.tags.filter($=>$!==s.tag):[...t.tags,s.tag]}),className:`px-2 py-0.5 rounded-full text-[11px] font-mono border ${j?`${p.bg} ${p.text} ${p.border?"border-current/30":"border-transparent"}`:"bg-bg-hi text-fg-faint border-line"}`,children:["#",s.tag]},s.tag)})})}),e.jsx(ce,{obj:t,set:r}),e.jsx(b,{label:"definition",hint:"The system prompt this persona runs under.",children:e.jsx("textarea",{rows:9,value:t.body,onChange:s=>r({body:s.target.value}),className:"w-full bg-bg border border-line rounded px-2 py-1.5 text-xs text-fg font-mono leading-relaxed resize-y"})}),e.jsx(b,{label:"project overrides",hint:"Open projects that shadow this definition with a local copy.",children:g&&g.overridingProjects.length>0?e.jsx("div",{className:"flex flex-wrap gap-1.5",children:g.overridingProjects.map(s=>e.jsxs("span",{className:"inline-flex items-center gap-1.5 bg-bg-elev border border-line rounded px-2 py-0.5 text-[11px] font-mono text-fg-dim",children:[s,e.jsx("button",{onClick:()=>D(s),title:"Drop the local copy",className:"text-fg-faint hover:text-fg",children:"×"})]},s))}):e.jsx("div",{className:"text-xs text-fg-faint italic",children:l?"save first to see project overrides.":"no open project overlays this agent — the global definition applies everywhere."})})]}),e.jsx("div",{className:"px-4 py-2.5 border-t border-line flex items-center gap-2 flex-wrap",children:c?e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"text-xs text-fg-dim",children:["Delete ",e.jsx("strong",{className:"font-mono",children:t.name})," and its file?"]}),e.jsx(y,{variant:"danger",onClick:N,disabled:m,children:"Delete"}),e.jsx(y,{onClick:()=>i(!1),children:"Keep"})]}):e.jsxs(e.Fragment,{children:[e.jsx(y,{onClick:u,disabled:m,children:"Duplicate"}),!l&&e.jsx(y,{variant:"danger",onClick:()=>i(!0),disabled:m,children:"Delete"}),e.jsx("div",{className:"flex-1"}),k&&e.jsx("span",{className:"text-[11px] text-fg-faint",children:"unsaved changes"}),e.jsx(y,{onClick:a,disabled:!k||m,children:"Revert"}),e.jsx(y,{variant:"primary",onClick:v,disabled:!k||m,children:m?"Saving…":l?"Create":"Save"})]})})]})}function ce({obj:t,set:r}){const{projects:g}=ee(),f=g.map(a=>({cwd:a.cwd,name:a.name})),l=new Set(f.map(a=>a.cwd)),m=t.projects.filter(a=>a!==T&&!l.has(a)),c=t.projects.includes(T),i=a=>r({projects:t.projects.includes(a)?t.projects.filter(v=>v!==a):[...t.projects,a]}),u=t.projects.length>0;return e.jsxs(e.Fragment,{children:[e.jsx(b,{label:"action — appears in",hint:"Projects whose Sessions toolbar gets a one-click button for this agent. Pressing it starts a normal session: this persona is the ACTOR, its first tag is the MISSION, and the action text below is the opening goal. Leave empty for an agent that is only picked by hand in the New Session card.",children:e.jsxs("div",{className:"flex flex-wrap gap-1.5",children:[e.jsx("button",{onClick:()=>i(T),className:`px-2 py-0.5 rounded-full text-[11px] font-mono border ${c?"bg-accent/15 text-accent border-accent/40 font-semibold":"bg-bg-hi text-fg-faint border-line"}`,children:"every project"}),f.map(a=>{const v=t.projects.includes(a.cwd);return e.jsx("button",{title:a.cwd,onClick:()=>i(a.cwd),className:`px-2 py-0.5 rounded-full text-[11px] font-mono border ${v?"bg-sage/15 text-sage-dark border-sage/30":"bg-bg-hi text-fg-faint border-line"} ${c&&!v?"opacity-40":""}`,children:a.name},a.cwd)}),m.map(a=>e.jsxs("button",{title:`${a} — not a known project on this machine`,onClick:()=>i(a),className:"px-2 py-0.5 rounded-full text-[11px] font-mono border bg-bg-hi text-fg-faint border-dashed border-line",children:[a," ×"]},a))]})}),u&&e.jsxs(e.Fragment,{children:[e.jsx(b,{label:"action — button label",hint:"Caption on the Sessions toolbar button. Defaults to the agent name.",children:e.jsx("input",{value:t.actionLabel,onChange:a=>r({actionLabel:a.target.value}),placeholder:t.name,className:"w-full bg-bg border border-line rounded px-2 py-1 text-xs text-fg"})}),e.jsx(b,{label:"action — opening instruction",hint:"Sent as the session's first message, under the AIM framing. Falls back to this persona's description when empty; with neither, no button is shown.",children:e.jsx("textarea",{rows:3,value:t.action,onChange:a=>r({action:a.target.value}),placeholder:t.description||`e.g. /builder
2
-
3
- Check git vs the published package and publish anything new.`,className:"w-full bg-bg border border-line rounded px-2 py-1.5 text-xs text-fg font-mono leading-relaxed resize-y"})})]})]})}function b({label:t,hint:r,children:g}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-[10.5px] font-semibold uppercase tracking-wide text-fg-faint mb-1.5 font-mono",children:t}),g,r&&e.jsx("div",{className:"text-[11px] text-fg-faint mt-1 leading-snug",children:r})]})}function de({options:t,value:r,onChange:g,mono:f}){const l=r&&!t.includes(r),m=l?[...t,r]:t;return e.jsx("div",{className:"flex flex-wrap gap-1",children:m.map(c=>{const i=c===r,u=l&&c===r;return e.jsxs("button",{onClick:()=>g(c),title:u?`${c} — current on-disk value, not in the standard list`:void 0,className:`px-2.5 py-1 rounded text-xs border ${f?"font-mono":""} ${i?"bg-accent/15 text-accent border-accent/40 font-semibold":"bg-bg-hi text-fg-dim border-line"} ${u?"border-dashed":""}`,children:[c,u?" (current)":""]},c)})})}export{he as AgentLibrary};
@@ -1 +0,0 @@
1
- import{au as d,h as j,ai as $,a1 as g,ah as e,l as N,V as E,ak as S,a2 as b,aw as T,b as p,Y as D,i as v,E as R}from"./index-a2MVk8qh.js";import{P as V}from"./Panel-RMz3Acpu.js";import"./monaco-editor-BW5C4Iv1.js";const C=[{key:"diagram",label:"Diagram"},{key:"tables",label:"Tables"}];function G(){const[s,t]=d.useState("diagram"),[a,i]=d.useState(null),[l,n]=d.useState(()=>new Set),c=d.useMemo(()=>j.filter(r=>!l.has(r.group)),[l]),m=d.useMemo(()=>$(c),[c]),o=r=>{n(x=>{const h=new Set(x);return h.has(r)?h.delete(r):h.add(r),h}),i(null)},u=a?g(a):null,y=r=>c.some(x=>x.id===r);return e.jsx(V,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(E,{options:C,active:s,onChange:t}),e.jsx(M,{hiddenGroups:l,onToggle:o}),e.jsxs("span",{className:"ml-auto text-fg-faint",children:[j.length," entities"]})]}),children:s==="diagram"?e.jsxs("div",{className:"h-full flex",children:[e.jsx("div",{className:"flex-1 min-w-0 overflow-auto",children:e.jsx(O,{layout:m,selectedId:a,onSelect:r=>i(x=>x===r?null:r)})}),e.jsx("div",{className:"w-96 shrink-0 border-l border-line overflow-y-auto",children:u?e.jsx(F,{entity:u,onSelectRelated:r=>y(r)?i(r):void 0}):e.jsx(N,{title:"select an entity",hint:"click a box in the diagram to see its storage, fields, and relations"})})]}):e.jsx(P,{})})}const L=d.memo(G);function M({hiddenGroups:s,onToggle:t}){return e.jsx("div",{className:"flex items-center gap-1.5 flex-wrap",children:v.map(a=>{const i=s.has(a.id);return e.jsxs("button",{onClick:()=>t(a.id),title:`${a.blurb} (${a.realm})`,className:`flex items-center gap-1 px-1.5 py-0.5 rounded border text-[10.5px] ${i?"border-line text-fg-faint opacity-50":"border-line text-fg-dim hover:text-fg"}`,children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${a.tone.dot}`}),a.label,e.jsx("span",{className:"text-fg-faint",children:a.realm})]},a.id)})})}function O({layout:s,selectedId:t,onSelect:a}){const i=d.useMemo(()=>t?new Set(S(t)):null,[t]),l=n=>!!t&&(n.relation.from===t||n.relation.to===t);return s.boxes.length===0?e.jsx(N,{title:"no entities in view",hint:"toggle a group in the legend to show its entities"}):e.jsxs("div",{className:"relative p-4",style:{width:s.width+32,height:s.height+32},children:[e.jsxs("svg",{width:s.width,height:s.height,className:"absolute left-4 top-4 overflow-visible",children:[s.edges.map(n=>{const c=l(n);return e.jsx("path",{"data-testid":`erd-edge-${n.relation.from}-${n.relation.to}`,d:n.d,fill:"none",className:c?"stroke-accent":"stroke-line",strokeWidth:c?2:1,opacity:t&&!c?.25:1},`${n.relation.from}-${n.relation.to}-${n.relation.label}`)}),s.edges.map(n=>l(n)?e.jsx("text",{x:n.mx,y:n.my,textAnchor:"middle",className:"fill-fg-dim text-[10px]",children:n.relation.label},`label-${n.relation.from}-${n.relation.to}-${n.relation.label}`):null)]}),s.boxes.map(n=>e.jsx(_,{box:n,selected:n.id===t,dimmed:!!t&&n.id!==t&&!(i!=null&&i.has(n.id)),onClick:()=>a(n.id)},n.id))]})}function _({box:s,selected:t,dimmed:a,onClick:i}){const l=g(s.id),n=b(s.group),c=l.fields.slice(0,R),m=l.fields.length-c.length;return e.jsxs("button",{type:"button","data-testid":`erd-box-${s.id}`,onClick:i,className:`absolute text-left rounded border overflow-hidden bg-bg-hi ${t?"border-accent ring-1 ring-accent":"border-line"} ${a?"opacity-30":""}`,style:{left:s.x,top:s.y,width:s.w,height:s.h},children:[e.jsxs("div",{className:"px-2 py-1 border-b border-line flex items-center gap-1.5",children:[e.jsx("span",{className:`w-1.5 h-1.5 rounded-full shrink-0 ${n.tone.dot}`}),e.jsx("span",{className:"text-[11px] font-semibold text-fg truncate",children:l.name})]}),l.aka&&e.jsx("div",{className:"px-2 pt-0.5 text-[9.5px] text-fg-faint truncate",children:l.aka}),e.jsxs("div",{className:"px-2 py-0.5",children:[c.map(o=>e.jsxs("div",{className:"text-[9.5px] font-mono text-fg-dim truncate flex items-center gap-1",children:[o.key&&e.jsx("span",{className:"text-fg-faint",children:o.key}),e.jsx("span",{className:"truncate",children:o.name})]},o.name)),m>0&&e.jsxs("div",{className:"text-[9.5px] text-fg-faint italic",children:["+",m," more"]})]})]})}function w({fields:s}){return e.jsxs("table",{className:"w-full text-[11px] font-mono",children:[e.jsx("thead",{className:"text-fg-faint uppercase tracking-wide text-[9.5px]",children:e.jsxs("tr",{className:"border-b border-line",children:[e.jsx("th",{className:"text-left font-normal px-2 py-1",children:"name"}),e.jsx("th",{className:"text-left font-normal px-2 py-1",children:"type"}),e.jsx("th",{className:"text-left font-normal px-2 py-1",children:"key"}),e.jsx("th",{className:"text-left font-normal px-2 py-1",children:"note"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{className:"border-b border-line/50",children:[e.jsxs("td",{className:"px-2 py-1 text-fg",children:[t.name,t.optional&&e.jsx("span",{className:"text-fg-faint",children:"?"})]}),e.jsx("td",{className:"px-2 py-1 text-fg-dim",children:t.type}),e.jsx("td",{className:"px-2 py-1",children:t.key&&e.jsxs(p,{tone:t.key==="pk"?"accent":"dim",children:[t.key,t.ref?` → ${t.ref}`:""]})}),e.jsx("td",{className:"px-2 py-1 text-fg-faint",children:t.note})]},t.name))})]})}function k({entity:s}){return e.jsxs("div",{className:"space-y-1 text-[11px]",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"text-fg-faint w-20 shrink-0",children:"path"}),e.jsx("span",{className:"font-mono text-fg-dim break-all",children:s.store.path})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"text-fg-faint w-20 shrink-0",children:"format"}),e.jsx("span",{className:"font-mono text-fg-dim",children:s.store.format})]}),s.store.writer&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"text-fg-faint w-20 shrink-0",children:"writer"}),e.jsxs(p,{tone:"accent",children:["single-writer: ",s.store.writer]})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"text-fg-faint w-20 shrink-0",children:"definedIn"}),e.jsx("span",{className:"font-mono text-fg-dim break-all",children:s.store.definedIn})]})]})}function F({entity:s,onSelectRelated:t}){const a=b(s.group),i=T(s.id);return e.jsxs("div",{className:"p-3 space-y-3",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${a.tone.dot}`}),e.jsx("span",{className:"text-sm font-semibold text-fg",children:s.name})]}),s.aka&&e.jsx("div",{className:"text-[10.5px] text-fg-faint",children:s.aka}),e.jsx(p,{tone:"dim",className:"mt-1",children:a.label})]}),e.jsx("div",{className:"text-xs text-fg-dim leading-relaxed",children:s.summary}),e.jsxs("div",{children:[e.jsx(f,{children:"storage"}),e.jsx(k,{entity:s})]}),e.jsxs("div",{children:[e.jsx(f,{children:"fields"}),e.jsx(w,{fields:s.fields})]}),s.notes&&s.notes.length>0&&e.jsxs("div",{children:[e.jsx(f,{children:"notes"}),e.jsx("ul",{className:"list-disc pl-4 space-y-0.5 text-xs text-fg-dim",children:s.notes.map(l=>e.jsx("li",{children:l},l))})]}),e.jsxs("div",{children:[e.jsx(f,{children:"relations"}),i.length===0?e.jsx("div",{className:"text-xs text-fg-faint italic",children:"no relations"}):e.jsx("ul",{className:"space-y-1",children:i.map(l=>{const n=l.from===s.id?l.to:l.from,c=g(n);return e.jsxs("li",{className:"flex items-center gap-1.5 text-xs",children:[e.jsx("span",{className:"font-mono text-fg-faint w-10 shrink-0",children:D(l.cardinality)}),e.jsx("span",{className:"text-fg-dim",children:l.label}),l.via&&e.jsxs("span",{className:"font-mono text-[10px] text-fg-faint",children:["via ",l.via]}),e.jsx("button",{type:"button",onClick:()=>t(n),className:"ml-auto text-accent hover:underline font-mono",children:c.name})]},`${l.from}-${l.to}-${l.label}`)})})]})]})}function f({children:s}){return e.jsx("div",{className:"text-[10.5px] uppercase tracking-wide text-fg-faint mb-1 font-mono",children:s})}function P(){return e.jsx("div",{className:"p-4 space-y-6",children:v.map(s=>{const t=j.filter(a=>a.group===s.id);return t.length===0?null:e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-1.5 mb-2",children:[e.jsx("span",{className:`w-2 h-2 rounded-full ${s.tone.dot}`}),e.jsx("span",{className:"text-xs font-semibold text-fg",children:s.label}),e.jsx("span",{className:"text-[10.5px] text-fg-faint",children:s.realm})]}),e.jsx("div",{className:"grid grid-cols-1 xl:grid-cols-2 gap-3",children:t.map(a=>e.jsxs("div",{className:"border border-line rounded bg-bg-hi p-3 space-y-2",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-semibold text-fg",children:a.name}),a.aka&&e.jsx("span",{className:"text-[10.5px] text-fg-faint",children:a.aka})]}),e.jsx(p,{tone:"dim",className:"mt-1",children:s.label})]}),e.jsx("div",{className:"text-xs text-fg-dim leading-relaxed",children:a.summary}),e.jsx(k,{entity:a}),e.jsx(w,{fields:a.fields}),a.notes&&a.notes.length>0&&e.jsx("ul",{className:"list-disc pl-4 space-y-0.5 text-xs text-fg-dim",children:a.notes.map(i=>e.jsx("li",{children:i},i))})]},a.id))})]},s.id)})})}export{L as DataModel};
@@ -1 +0,0 @@
1
- import{ah as e}from"./index-a2MVk8qh.js";function o({sidebar:r,detail:s,sidebarWidth:i="18rem"}){return e.jsxs("div",{className:"h-full flex",children:[e.jsx("div",{className:"shrink-0 border-r border-line overflow-y-auto",style:{width:i},children:r}),e.jsx("div",{className:"flex-1 min-w-0 overflow-auto",children:s})]})}export{o as L};
@@ -1 +0,0 @@
1
- import{ah as e}from"./index-a2MVk8qh.js";function n({toolbar:s,footer:l,children:r}){return e.jsxs("div",{className:"h-full flex flex-col",children:[s&&e.jsx("div",{className:"shrink-0 border-b border-line bg-bg-elev px-3 py-1.5 flex items-center gap-2 text-xs",children:s}),e.jsx("div",{className:"flex-1 min-h-0 overflow-auto",children:r}),l&&e.jsx("div",{className:"shrink-0 border-t border-line bg-bg-elev",children:l})]})}export{n as P};
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./SkillReferenceGraph-BI1YtCbB.js","./index-a2MVk8qh.js","./monaco-editor-BW5C4Iv1.js","./monaco-editor-BTnBOi8r.css","./index-D3P_jldk.css"])))=>i.map(i=>d[i]);
2
- import{ah as e,au as p,l as y,aN as X,aH as R,b as Y}from"./index-a2MVk8qh.js";import{P as V}from"./Panel-RMz3Acpu.js";import{P as z}from"./ProvenanceBadge-CO-DZN38.js";import{e as Z}from"./Library-DrGdaz9N.js";import{p as G}from"./skillFrontmatter-Dif5JIg7.js";import{_ as ee}from"./monaco-editor-BW5C4Iv1.js";import{L as te}from"./ListDetail-D4bxU_-2.js";import{M as ne}from"./MarkdownEditor-H1ytN4Tk.js";function se({columns:t,rows:n,getKey:o,onRowClick:a,activeKey:i,empty:m}){return n.length===0?e.jsx("div",{className:"p-6 text-fg-faint text-xs text-center",children:m??"no entries"}):e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"sticky top-0 bg-bg-elev text-fg-faint uppercase tracking-wider",children:e.jsx("tr",{className:"border-b border-line",children:t.map(l=>e.jsx("th",{className:`text-left font-normal px-3 py-1.5 ${l.className??""}`,style:l.width?{width:l.width}:void 0,children:l.header},l.key))})}),e.jsx("tbody",{children:n.map(l=>{const r=o(l),d=i===r;return e.jsx("tr",{"data-row-key":r,onClick:()=>a==null?void 0:a(l),className:`border-b border-line/50 transition-colors ${a?"cursor-pointer":""} ${d?"bg-bg-hi text-fg":"text-fg-dim hover:bg-bg-hi/50"}`,children:t.map(f=>e.jsx("td",{className:`px-3 py-1 ${f.className??""}`,children:f.render(l)},f.key))},r)})})]})}async function ie(t,n,o){var f,b;const a=`${n}/skills`;try{const c=await window.api.config.listDir(a,{dirsOnly:!0});if(c.ok&&c.entries.length>0)return a}catch{}let i=null;try{const c=await window.api.config.readJson(`${o}/.claude/plugins/installed_plugins.json`);c.exists&&!c.parseError&&c.data&&typeof c.data=="object"&&(i=c.data)}catch{return null}if(!(i!=null&&i.plugins))return null;const m=Object.keys(i.plugins).find(c=>c===t||c.startsWith(`${t}@`));if(!m)return null;const l=(b=(f=i.plugins[m])==null?void 0:f[0])==null?void 0:b.installPath;if(!l)return null;const r=`${l}/skills`;return await window.api.config.exists(r)?r:null}async function ae(t){const n=await window.api.config.listDir(t,{dirsOnly:!0}),o=[];for(const a of n.entries){const i=`${a.path}/SKILL.md`,m=await window.api.config.readText(i);if(!m.exists)continue;const l=G(m.text);o.push({id:a.name,name:l.name,description:l.description,dir:a.path,path:i,body:l.body})}return o}function le(t){const n=[],o=new Set;for(const a of t)for(const i of t){if(a.id===i.id)continue;const m=i.id.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),l=[`/${m}\\b`,`\`${m}\``];if(i.id.length>=4&&l.push(`\\b${m}\\b`),!l.some(f=>new RegExp(f,"i").test(a.body)))continue;const d=`${a.id}->${i.id}`;o.has(d)||(o.add(d),n.push({from:a.id,to:i.id}))}return n}const re=p.lazy(()=>ee(()=>import("./SkillReferenceGraph-BI1YtCbB.js"),__vite__mapDeps([0,1,2,3,4]),import.meta.url).then(t=>({default:t.SkillReferenceGraph})));function oe({pluginName:t,skills:n,onBack:o,initialSelectedId:a}){var b;const[i,m]=p.useState(a??((b=n[0])==null?void 0:b.id)??null),l=i?n.find(c=>c.id===i)??null:null,r=p.useMemo(()=>le(n),[n]),[d,f]=p.useState("list");return e.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden",children:[e.jsxs("div",{className:"shrink-0 h-11 flex items-baseline gap-3.5 px-3 border-b border-line bg-bg",children:[e.jsxs("button",{type:"button",onClick:o,className:"font-mono text-accent hover:underline shrink-0 text-xs",children:["← ",t]}),e.jsx("span",{className:"font-serif text-[22px] text-fg shrink-0 truncate max-w-[16rem]",children:(l==null?void 0:l.name)??(l==null?void 0:l.id)??"skill"}),e.jsx("span",{className:"flex-1"}),e.jsx("div",{className:"flex items-center gap-1.5 shrink-0",children:e.jsxs("div",{className:"flex rounded border border-line overflow-hidden",children:[e.jsx("button",{onClick:()=>f("list"),className:`px-2 py-0.5 text-xs ${d==="list"?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:"list"}),e.jsx("button",{onClick:()=>f("graph"),className:`px-2 py-0.5 text-xs ${d==="graph"?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:"graph"})]})})]}),e.jsxs("div",{className:"shrink-0 h-[26px] flex items-center gap-[18px] px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:[l!=null&&l.description?e.jsx("span",{className:"text-fg-dim truncate normal-case",children:l.description}):null,e.jsxs("span",{className:"ml-auto text-fg-faint truncate normal-case",children:[n.length," ",n.length===1?"skill":"skills"," · ",r.length," ",r.length===1?"reference":"references"]})]}),e.jsx("div",{className:"flex-1 min-h-0 overflow-hidden",children:n.length===0?e.jsx(y,{title:"no skills in this plugin"}):d==="graph"?e.jsx(p.Suspense,{fallback:e.jsx("div",{className:"p-6 text-xs text-fg-faint",children:"Loading graph…"}),children:e.jsx(re,{skills:n,edges:r,selectedId:i,onSelect:m})}):e.jsx(te,{sidebar:e.jsx("div",{className:"py-1",children:n.map(c=>e.jsxs("button",{onClick:()=>m(c.id),className:`w-full px-3 py-1 text-xs text-left ${i===c.id?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[e.jsx("div",{className:"truncate",children:c.name??c.id}),c.description?e.jsx("div",{className:"truncate text-fg-faint",children:c.description}):null]},c.id))}),detail:l?e.jsx("div",{className:"h-full min-h-0",children:e.jsx(ne,{path:l.path,value:l.body,onChange:()=>{},readOnly:!0})}):e.jsx(y,{title:"select a skill"})})})]})}const q=t=>{var n,o;return{type:"plugin",name:t.name,repository:(n=t.manifest)==null?void 0:n.repository,homepage:(o=t.manifest)==null?void 0:o.homepage}};function ce(){const t=X(),[n,o]=p.useState([]),[a,i]=p.useState(!0),[m,l]=p.useState(null),[r,d]=p.useState("installed"),[f,b]=p.useState(null),[c,L]=p.useState(new Set);p.useEffect(()=>{var x,k;let s=!1;return(k=(x=window.api.app).seedStatus)==null||k.call(x).then(j=>{s||b(j)}).catch(()=>{}),()=>{s=!0}},[]),p.useEffect(()=>{if(!t)return;let s=!1;return(async()=>{var k;i(!0);const x=[];try{const j=await window.api.config.readJson(`${t}/.claude/plugins/installed_plugins.json`);if(j.exists&&!j.parseError&&j.data&&typeof j.data=="object"){const w=j.data;for(const[C,A]of Object.entries(w.plugins??{})){if(!Array.isArray(A))continue;const _=C.split("@")[0],u=C.split("@")[1];for(const g of A){if(!(g!=null&&g.installPath))continue;const B={name:_,path:g.installPath,isDirectory:!0,isFile:!1,mtimeMs:0,size:0},v=await fe(B);(k=v.manifest)!=null&&k.version||(v.manifest={...v.manifest??{},version:g.version}),v.marketplace=u,x.push(v)}}}}catch{}s||(x.sort((j,w)=>j.name.localeCompare(w.name)),s||(o(x),i(!1)))})(),()=>{s=!0}},[t]);const S=[{key:"name",header:"name",render:s=>{var x;return e.jsxs("div",{style:{maxWidth:"16rem"},children:[e.jsx("div",{className:"truncate",children:s.name}),(x=s.manifest)!=null&&x.description?e.jsx("div",{className:"truncate text-fg-faint",title:s.manifest.description,children:s.manifest.description}):null]})},width:"16rem"},{key:"origin",header:"origin",render:s=>e.jsx(z,{interactive:!1,input:q(s)}),width:"7rem"},{key:"version",header:"version",render:s=>{var x;return((x=s.manifest)==null?void 0:x.version)??e.jsx("span",{className:"text-fg-faint",children:"—"})},width:"6rem"},{key:"manifest",header:"manifest",render:s=>s.hasManifest?"plugin.json":e.jsx("span",{className:"text-fg-faint",children:"—"}),width:"8rem"},{key:"contents",header:"contents",render:s=>e.jsx("span",{className:"font-mono text-fg-faint text-xs",children:[s.agents>0?`${s.agents} agents`:null,s.skills>0?`${s.skills} skills`:null,s.hooks>0?`${s.hooks} hooks`:null,s.monitors>0?`${s.monitors} monitors`:null,s.binCount>0?`${s.binCount} bin`:null,s.hasLsp?"lsp":null,s.hasMcp?"mcp":null].filter(Boolean).join(" · ")||"—"})},{key:"path",header:"path",render:s=>e.jsx("span",{className:"font-mono text-fg-faint truncate",children:s.path})}],$=p.useMemo(()=>f?Object.keys(f).filter(s=>f[s].status==="exhausted"&&!c.has(s)):[],[f,c]),E=$.length>0?e.jsx(de,{seeders:$,seedStatus:f,onDismiss:s=>L(x=>new Set(x).add(s)),onOpenLibrary:()=>d("library")}):null;if(r==="library")return e.jsxs(V,{toolbar:e.jsx(W,{active:r,onChange:d}),children:[E,e.jsx(Z,{})]});const h=m?n.find(s=>s.path===m)??null:null;return e.jsxs(V,{toolbar:e.jsxs(e.Fragment,{children:[e.jsx(W,{active:r,onChange:d}),e.jsx("span",{className:"mx-2 text-fg-faint",children:"·"}),e.jsxs("span",{className:"text-fg-faint",children:[n.length," plugins"]}),e.jsx("div",{className:"flex-1"}),e.jsx("span",{className:"text-fg-faint font-mono truncate",children:"~/.claude/plugins/installed_plugins.json"})]}),children:[E,a?e.jsx(y,{title:"scanning plugins…"}):h?e.jsx(me,{row:h,home:t,onBack:()=>l(null)},h.path):e.jsx("div",{className:"flex flex-col h-full",children:e.jsx("div",{className:"flex-1 min-h-0 overflow-auto",children:e.jsx(se,{columns:S,rows:n,getKey:s=>s.path,activeKey:m,onRowClick:s=>l(s.path),empty:e.jsxs(e.Fragment,{children:["no plugins installed",e.jsxs("div",{className:"mt-2 text-fg-faint",children:["drop a plugin into ",e.jsx("code",{children:"~/.claude/plugins/"})]})]})})})})]})}const ke=p.memo(ce),K={"dev-plugin":"session-manager-dev plugin","scheduler-mcp":"Scheduler MCP server","agent-personas":"Agent personas (Architect, Dev Lead)"};function de({seeders:t,seedStatus:n,onDismiss:o,onOpenLibrary:a}){return e.jsx("div",{className:"shrink-0 flex flex-col gap-1.5 px-3 py-2 border-b border-line bg-yellow-950/20",children:t.map(i=>e.jsxs("div",{className:"flex items-start gap-2 text-xs text-yellow-300",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"font-medium",children:[K[i]," setup failed after retrying — manual fix needed"]}),i==="dev-plugin"?e.jsxs("div",{className:"text-yellow-400/80 mt-0.5",children:["Click ",e.jsx("button",{onClick:a,className:"underline hover:no-underline",children:"here"}),' to open the Library tab, then click Install next to "session-manager-dev".']}):e.jsx("div",{className:"text-yellow-400/80 mt-0.5 font-mono",children:n[i].fix})]}),e.jsx("button",{onClick:()=>o(i),className:"shrink-0 text-yellow-400/70 hover:text-yellow-300","aria-label":`Dismiss ${K[i]} warning`,children:"✕"})]},i))})}function W({active:t,onChange:n}){const o=[["installed","Installed"],["library","Library"]];return e.jsx("div",{className:"flex rounded border border-line overflow-hidden",role:"tablist","aria-label":"Plugins view",children:o.map(([a,i])=>e.jsx("button",{onClick:()=>n(a),role:"tab","aria-selected":t===a,className:`px-2 py-0.5 text-xs ${t===a?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:i},a))})}function me({row:t,home:n,onBack:o}){var j,w,C,A,_;const[a,i]=p.useState([]),[m,l]=p.useState([]),[r,d]=p.useState([]),[f,b]=p.useState([]),[c,L]=p.useState("skills"),[S,$]=p.useState(null),[E,h]=p.useState(!0);p.useEffect(()=>{if(!n)return;let u=!1;return(async()=>{h(!0);try{const[g,B,v,Q]=await Promise.all([ie(t.name,t.path,n),O(`${t.path}/agents`,{filesOnly:!0}),t.hasMcp?window.api.config.readJson(`${t.path}/.mcp.json`):Promise.resolve(null),O(`${t.path}/bin`,{filesOnly:!0})]),J=g?await ae(g):[],T=B.filter(N=>N.endsWith(".md")),U=await Promise.all(T.map(N=>window.api.config.readText(`${t.path}/agents/${N}`))),I=[];T.forEach((N,F)=>{const M=U[F];if(!M.exists)return;const D=G(M.text);I.push({id:N,name:D.name??N.replace(/\.md$/,""),description:D.description})});const H=[];if(v&&v.exists&&!v.parseError&&v.data&&typeof v.data=="object"){const N=v.data.mcpServers;if(N&&typeof N=="object")for(const[F,M]of Object.entries(N)){const D=M&&typeof M=="object"?M.command:void 0;H.push({id:F,name:F,description:typeof D=="string"?D:null})}}if(u)return;i(J),l(I),d(H),b(Q),L(J.length>0?"skills":I.length>0?"agents":H.length>0?"mcp":t.hooks>0?"hooks":t.monitors>0?"monitors":t.hasLsp?"lsp":"files")}catch(g){if(u)return;R.error(`Failed to load plugin contents: ${g instanceof Error?g.message:String(g)}`),i([]),l([]),d([]),b([])}finally{u||h(!1)}})(),()=>{u=!0}},[t.path,t.name,t.hasMcp,t.hooks,t.monitors,t.hasLsp,n]);const s=[{key:"skills",label:"Skills",count:a.length},{key:"agents",label:"Agents",count:m.length},{key:"mcp",label:"MCP server",count:r.length},{key:"hooks",label:"Hooks",count:t.hooks},{key:"monitors",label:"Monitors",count:t.monitors},{key:"lsp",label:"LSP",count:t.hasLsp?1:0},{key:"files",label:"Bin",count:f.length}],x=(j=t.manifest)!=null&&j.author?typeof t.manifest.author=="string"?t.manifest.author:t.manifest.author.name??null:null,k=async u=>{const g=await window.api.shell.open({as:"external",url:u});g.ok||R.error(g.error??`Failed to open ${u}`)};return S?e.jsx(oe,{pluginName:((w=t.manifest)==null?void 0:w.name)??t.name,skills:a,initialSelectedId:S.id,onBack:()=>$(null)},S.id):e.jsxs("div",{className:"flex flex-col h-full min-h-0 overflow-hidden",children:[e.jsxs("div",{className:"shrink-0 h-11 flex items-baseline gap-3.5 px-3 border-b border-line bg-bg",children:[e.jsx("button",{type:"button",onClick:o,className:"font-mono text-accent hover:underline shrink-0 text-xs",children:"← Plugins"}),e.jsx("span",{className:"font-serif text-[22px] text-fg shrink-0 truncate max-w-[16rem]",children:((C=t.manifest)==null?void 0:C.name)??t.name}),(A=t.manifest)!=null&&A.version?e.jsxs("span",{className:"font-mono text-fg-faint text-xs shrink-0",children:["v",t.manifest.version]}):null,(_=t.manifest)!=null&&_.description?e.jsx("span",{className:"text-fg-dim text-xs min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap",children:t.manifest.description}):e.jsx("span",{className:"flex-1"}),e.jsxs("div",{className:"flex items-center gap-1.5 shrink-0",children:[e.jsx(z,{input:q(t)}),t.hasMcp?e.jsx(Y,{tone:"accent",children:"MCP"}):null]})]}),t.manifest?e.jsxs("div",{className:"shrink-0 h-[26px] flex items-center gap-[18px] px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:[x?e.jsxs("span",{className:"text-fg-dim truncate",children:[e.jsx("span",{className:"text-fg-faint",children:"Author "}),x]}):null,t.manifest.license?e.jsxs("span",{className:"text-fg-dim truncate",children:[e.jsx("span",{className:"text-fg-faint",children:"License "}),t.manifest.license]}):null,t.manifest.homepage?e.jsxs("button",{onClick:()=>k(t.manifest.homepage),className:"text-accent hover:underline truncate normal-case",title:t.manifest.homepage,children:[e.jsx("span",{className:"text-fg-faint uppercase",children:"Homepage "}),t.manifest.homepage]}):null,e.jsx("span",{className:"ml-auto text-fg-faint truncate normal-case",children:t.path})]}):e.jsx("div",{className:"shrink-0 h-[26px] flex items-center px-3 bg-bg-elev border-b border-line text-[9px] font-mono uppercase tracking-wide overflow-hidden",children:e.jsx("span",{className:"ml-auto text-fg-faint truncate normal-case",children:t.path})}),e.jsxs("div",{className:"flex-1 min-h-0 grid overflow-hidden",style:{gridTemplateColumns:"170px 1fr"},children:[e.jsx("div",{className:"min-h-0 overflow-auto bg-bg-elev border-r border-line py-1",children:s.map(u=>e.jsxs("button",{type:"button",disabled:u.count===0,onClick:()=>L(u.key),className:`w-full text-left px-3 py-1.5 text-xs flex items-center justify-between ${u.count===0?"text-fg-faint opacity-50 cursor-default":c===u.key?"bg-bg-hi text-fg":"text-fg-dim hover:text-fg hover:bg-bg-hi"}`,children:[e.jsx("span",{children:u.label}),u.count>0?e.jsx("span",{className:"font-mono text-fg-faint",children:u.count}):null]},u.key))}),e.jsx("div",{className:"min-h-0 overflow-auto",children:E?e.jsx(y,{title:"scanning…"}):e.jsx(he,{active:c,row:t,skills:a,agents:m,mcpServers:r,files:f,onOpenSkill:$})})]})]})}function he({active:t,row:n,skills:o,agents:a,mcpServers:i,files:m,onOpenSkill:l}){return t==="skills"?o.length===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:o.map((r,d)=>e.jsx(P,{n:d+1,name:r.name??r.id,description:r.description,onClick:()=>l(r)},r.id))}):t==="agents"?a.length===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:a.map((r,d)=>e.jsx(P,{n:d+1,name:r.name??r.id,description:r.description},r.id))}):t==="mcp"?i.length===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:i.map((r,d)=>e.jsx(P,{n:d+1,name:r.name,description:r.description},r.id))}):t==="hooks"?n.hooks===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:e.jsx(P,{n:1,name:`${n.hooks} ${n.hooks===1?"hook":"hooks"} configured`,description:`${n.path}/hooks/hooks.json`})}):t==="monitors"?n.monitors===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:e.jsx(P,{n:1,name:`${n.monitors} ${n.monitors===1?"monitor":"monitors"} configured`,description:`${n.path}/monitors/monitors.json`})}):t==="lsp"?n.hasLsp?e.jsx("div",{children:e.jsx(P,{n:1,name:"LSP server enabled",description:`${n.path}/.lsp.json`})}):e.jsx(y,{title:"no components"}):m.length===0?e.jsx(y,{title:"no components"}):e.jsx("div",{children:m.map((r,d)=>e.jsx(P,{n:d+1,name:r,description:null},r))})}function P({n:t,name:n,description:o,onClick:a}){const i=a?"button":"div";return e.jsxs(i,{onClick:a,className:`w-full flex items-baseline gap-2.5 py-[9px] px-3 border-b border-line text-left min-w-0 ${a?"hover:bg-bg-hi cursor-pointer":""}`,children:[e.jsx("span",{className:"font-serif text-fg-faint text-xs shrink-0 w-6 text-right",children:String(t).padStart(2,"0")}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"font-mono font-semibold text-accent truncate",children:n}),o?e.jsx("div",{className:"text-fg-dim text-xs truncate",children:o}):null]})]})}async function fe(t){let n=`${t.path}/.claude-plugin/plugin.json`,o=await window.api.config.exists(n);o||(n=`${t.path}/plugin.json`,o=await window.api.config.exists(n));let a=null;if(o){const h=await window.api.config.readJson(n);h.exists&&!h.parseError&&h.data&&typeof h.data=="object"&&(a=h.data)}const[i,m,l,r]=await Promise.all([window.api.config.exists(`${t.path}/.lsp.json`),window.api.config.exists(`${t.path}/.mcp.json`),window.api.config.exists(`${t.path}/monitors/monitors.json`),window.api.config.exists(`${t.path}/hooks/hooks.json`)]);let d=0;if(l){const h=await window.api.config.readJson(`${t.path}/monitors/monitors.json`);Array.isArray(h.data)?d=h.data.length:h.data&&typeof h.data=="object"&&Array.isArray(h.data.monitors)&&(d=h.data.monitors.length)}let f=0;if(r){const h=await window.api.config.readJson(`${t.path}/hooks/hooks.json`);if(h.data&&typeof h.data=="object"){const s=h.data;f=Object.values(s).reduce((x,k)=>Array.isArray(k)?x+k.reduce((j,w)=>j+(Array.isArray(w.hooks)?w.hooks.length:0),0):x,0)}}const[b,c,L]=await Promise.all([O(`${t.path}/agents`,{filesOnly:!0}),O(`${t.path}/bin`,{filesOnly:!0}),O(`${t.path}/skills`,{dirsOnly:!0})]),S=b.filter(h=>h.endsWith(".md")).length,$=c.length,E=L.length;return{name:t.name,path:t.path,mtimeMs:t.mtimeMs,hasManifest:o,manifest:a,hasLsp:i,monitors:d,hooks:f,agents:S,skills:E,binCount:$,hasMcp:m}}async function O(t,n){try{return(await window.api.config.listDir(t,n)).entries.map(a=>a.name)}catch{return[]}}export{ke as Plugins};
@@ -1 +0,0 @@
1
- import{$ as P,aN as G,au as x,ah as i,Z as R,B as T,b as _}from"./index-a2MVk8qh.js";import{a as E,C as B,c as L,d as S,b as I}from"./Library-DrGdaz9N.js";const N=e=>`${e}/.claude/session-manager/provenance.json`;function D(e){if(!e||typeof e!="object")return{};const t={};for(const[n,o]of Object.entries(e))(o==="anthropic"||o==="community"||o==="local")&&(t[n]=o);return t}const K=P((e,t)=>({overrides:{},loaded:!1,loading:!1,home:null,load:async n=>{const o=t();if(!(o.home===n&&(o.loaded||o.loading))){e({home:n,loading:!0});try{const r=await window.api.config.readJson(N(n)),d=r.exists?D(r.data):{};e(h=>({overrides:{...d,...h.overrides},loaded:!0,loading:!1}))}catch{e({loaded:!0,loading:!1})}}},setOverride:async(n,o)=>{const r={...t().overrides};o===null?delete r[n]:r[n]=o,e({overrides:r});const d=t().home;if(d)try{await window.api.config.writeJson(N(d),r)}catch{}}})),a=e=>(e??"").toLowerCase().trim(),$=new Set,j=new Set;for(const e of I){const t=e.official?$:j;t.add(a(e.id)),t.add(a(e.name))}const H=new Set(S.filter(e=>e.official).flatMap(e=>[a(e.id),a(e.name)])),J=new Set(S.filter(e=>!e.official).flatMap(e=>[a(e.id),a(e.name)])),U=new Set(L.filter(e=>e.official).flatMap(e=>[a(e.id),a(e.name)])),V=new Set(L.filter(e=>!e.official).flatMap(e=>[a(e.id),a(e.name)])),z=new Set(B.flatMap(e=>[a(e.id),a(e.name)])),Z=new Set(E.flatMap(e=>[a(e.id),a(e.name)])),q=new Set(E.map(e=>e.command.trim())),F=new Set(["security-review","pr-comments","release-notes","add-dir","code-review","simplify"]),Q=/(@anthropic-ai\/|anthropic\.com|github\.com\/anthropics)/i,W=/(^|\s)(npx|uvx|pipx|bunx|mcp-remote|deno\s+run|docker\s+run)(\s|$)/i;function X(e){return[e.command,...e.args??[],e.url,e.repository,e.homepage].filter(Boolean).join(" ").toLowerCase()}const l=e=>({provenance:"anthropic",reason:e}),y=e=>({provenance:"community",reason:e});function Y(e,t,n){switch(e){case"mcp":return $.has(t)?l("official MCP server (catalog)"):j.has(t)?y("third-party server (catalog)"):null;case"skill":case"command":return H.has(t)?l("official Anthropic skill (catalog)"):J.has(t)?y("third-party skill (catalog)"):null;case"plugin":return U.has(t)?l("official Anthropic plugin (catalog)"):V.has(t)?y("third-party plugin (catalog)"):null;case"subagent":return z.has(t)?l("bundled Anthropic subagent (catalog)"):null;case"hook":return Z.has(t)||n&&q.has(n.trim())?l("bundled hook (catalog)"):null}}function ee(e,t){return e.repository?"has a source repository":e.homepage?"has a homepage":e.url?"remote endpoint":W.test(t)?"installed from a package registry":null}function te(e){const t=a(e.name),n=X(e),o=Y(e.type,t,e.command);if(o)return o;if((e.type==="command"||e.type==="skill")&&F.has(t))return l("built-in Claude Code command");if(Q.test(n))return l("Anthropic package or repo");const r=ee(e,n);return r?y(r):{provenance:"local",reason:"no external source — assumed self-created"}}function ne(e,t,n){return`${e}:${t??"-"}:${n}`}const c={anthropic:"Anthropic",community:"Community",local:"Local"},O={anthropic:"accent",community:"warn",local:"dim"},oe=["anthropic","community","local"];function se({input:e,scope:t,interactive:n=!0,className:o=""}){const r=G(),{overrides:d,load:h,setOverride:k}=K(),[b,m]=x.useState(!1),v=x.useRef(null);x.useEffect(()=>{r&&h(r)},[r,h]),x.useEffect(()=>{if(!b)return;const s=C=>{v.current&&!v.current.contains(C.target)&&m(!1)},g=C=>{C.key==="Escape"&&m(!1)};return window.addEventListener("mousedown",s),window.addEventListener("keydown",g),()=>{window.removeEventListener("mousedown",s),window.removeEventListener("keydown",g)}},[b]);const w=ne(e.type,t??null,e.name),f=te(e),p=d[w],u=p??f.provenance,M=p?`Origin manually set to ${c[u]} — auto-detected ${c[f.provenance]} (${f.reason})`:`Auto-detected ${c[u]}: ${f.reason}`,A=i.jsxs(_,{tone:O[u],title:M,className:`${n?"cursor-pointer hover:brightness-125":""} ${o}`,children:[c[u],p&&i.jsx("span",{className:"w-1 h-1 rounded-full bg-current opacity-70","aria-hidden":!0})]});return n?i.jsxs("span",{ref:v,className:"relative inline-flex",children:[i.jsx("button",{type:"button",onClick:s=>{s.stopPropagation(),m(g=>!g)},className:"inline-flex","aria-label":`Origin: ${c[u]}. Click to change.`,children:A}),b&&i.jsxs("span",{className:`absolute ${R.dialog} top-full right-0 mt-1 min-w-[7.5rem] rounded-md border border-line bg-bg-elev shadow-lg py-1 text-left`,onClick:s=>s.stopPropagation(),children:[i.jsx("span",{className:"block px-2 pb-1 text-[10px] uppercase tracking-wide text-fg-faint",children:"Mark origin as"}),oe.map(s=>i.jsxs("button",{type:"button",onClick:()=>{k(w,s),m(!1)},className:`flex w-full items-center gap-2 px-2 py-1 text-[12px] hover:bg-bg-hi/60 ${u===s?"text-fg":"text-fg-dim"}`,children:[i.jsx("span",{className:`w-2 h-2 rounded-full border ${T[O[s]]}`,"aria-hidden":!0}),c[s],p===s&&i.jsx("span",{className:"ml-auto text-[10px] text-fg-faint",children:"set"})]},s)),i.jsx("div",{className:"my-1 border-t border-line"}),i.jsxs("button",{type:"button",onClick:()=>{k(w,null),m(!1)},disabled:!p,className:"flex w-full items-center gap-2 px-2 py-1 text-[12px] text-fg-dim hover:bg-bg-hi/60 disabled:opacity-40 disabled:hover:bg-transparent",title:`Revert to auto-detection (${c[f.provenance]})`,children:["Auto-detect",i.jsx("span",{className:"ml-auto text-[10px] text-fg-faint",children:c[f.provenance]})]})]})]}):A}export{se as P};