claude-code-session-manager 0.57.1 → 0.59.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 (68) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/{TiptapBody-CJDxVF7X.js → TiptapBody-PUx4oZTh.js} +1 -1
  3. package/dist/assets/index-BPnfPdLW.js +3222 -0
  4. package/dist/assets/{index-WUc_GHMf.css → index-CPMP2XZ_.css} +1 -1
  5. package/dist/index.html +2 -2
  6. package/package.json +1 -2
  7. package/plugins/session-manager-dev/skills/develop/SKILL.md +7 -6
  8. package/plugins/session-manager-dev/skills/develop/standards.md +1 -1
  9. package/plugins/session-manager-dev/skills/explain-to-me/SKILL.md +1 -1
  10. package/plugins/session-manager-dev/skills/find-opportunity/SKILL.md +1 -1
  11. package/plugins/session-manager-dev/skills/ops-sweep/SKILL.md +16 -25
  12. package/plugins/session-manager-dev/skills/project-status/SKILL.md +5 -5
  13. package/scripts/lib/watchdogHelpers.cjs +0 -434
  14. package/scripts/mint-epic.cjs +6 -6
  15. package/src/main/__tests__/activeIndexMerge.test.cjs +2 -2
  16. package/src/main/__tests__/agentModelResolve.test.cjs +119 -0
  17. package/src/main/__tests__/classifyTranscriptLine.test.cjs +128 -17
  18. package/src/main/__tests__/epicContextDigest.test.cjs +100 -0
  19. package/src/main/__tests__/epicMint.test.cjs +165 -207
  20. package/src/main/__tests__/epicValidationHook.test.cjs +291 -0
  21. package/src/main/__tests__/prdMigration.test.cjs +160 -0
  22. package/src/main/__tests__/projectPages.test.cjs +151 -0
  23. package/src/main/__tests__/promptSessionEvents.test.cjs +74 -0
  24. package/src/main/__tests__/promptSessionSchema.test.cjs +101 -0
  25. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +139 -0
  26. package/src/main/__tests__/rcaReport.test.cjs +188 -0
  27. package/src/main/__tests__/runVerify.test.cjs +109 -6
  28. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +32 -12
  29. package/src/main/__tests__/scheduler-epic-digest.test.cjs +214 -0
  30. package/src/main/__tests__/scheduler-heal-refusal.test.cjs +61 -0
  31. package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +74 -0
  32. package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +5 -5
  33. package/src/main/__tests__/transcripts-doFlush-array.test.cjs +118 -0
  34. package/src/main/__tests__/transcripts-paged-reads.test.cjs +233 -0
  35. package/src/main/__tests__/uniquePrdNumbers.test.cjs +7 -2
  36. package/src/main/chatRunner.cjs +10 -1
  37. package/src/main/health.cjs +5 -1
  38. package/src/main/index.cjs +3 -5
  39. package/src/main/ipcSchemas.cjs +72 -4
  40. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +130 -0
  41. package/src/main/lib/agentModelResolve.cjs +97 -0
  42. package/src/main/lib/auditLog.cjs +2 -2
  43. package/src/main/lib/classifyTranscriptLine.cjs +131 -48
  44. package/src/main/lib/epicContextDigest.cjs +78 -0
  45. package/src/main/lib/epicMint.cjs +86 -164
  46. package/src/main/lib/epicValidationHook.cjs +192 -0
  47. package/src/main/lib/prdMigration.cjs +76 -5
  48. package/src/main/lib/promptSessionSchema.cjs +95 -0
  49. package/src/main/lib/promptSessionsCreateEpic.cjs +70 -0
  50. package/src/main/lib/{rcaFeedbackHook.cjs → rcaReport.cjs} +47 -114
  51. package/src/main/lib/schedulerBatch.cjs +70 -111
  52. package/src/main/lib/schedulerConfig.cjs +0 -1
  53. package/src/main/otel.cjs +3 -1
  54. package/src/main/projectPages.cjs +60 -14
  55. package/src/main/promptSessionEvents.cjs +16 -1
  56. package/src/main/runVerify.cjs +17 -2
  57. package/src/main/scheduler.cjs +302 -68
  58. package/src/main/templates/project-pages-default-home.html +123 -0
  59. package/src/main/transcripts.cjs +191 -32
  60. package/src/main/webRemote.cjs +8 -7
  61. package/src/preload/api.d.ts +100 -57
  62. package/src/preload/index.cjs +9 -7
  63. package/dist/assets/index-DCa3QvAi.js +0 -3227
  64. package/plugins/session-manager-dev/skills/propose-epic/SKILL.md +0 -68
  65. package/scripts/propose-epic.cjs +0 -56
  66. package/src/main/__tests__/rcaFeedbackHook.test.cjs +0 -280
  67. package/src/main/repoAnalyzer.cjs +0 -346
  68. package/src/main/search.cjs +0 -332
@@ -171,10 +171,20 @@ export type TranscriptEventKind =
171
171
  | 'message'
172
172
  | string;
173
173
 
174
+ export interface TranscriptEventRef {
175
+ filePath: string;
176
+ byteOffset: number;
177
+ byteLength: number;
178
+ }
179
+
174
180
  export interface TranscriptEvent {
175
181
  kind: TranscriptEventKind;
176
182
  data: unknown;
177
183
  raw: unknown;
184
+ /** Short, bounded human-scannable preview of `data` — never the source of truth. */
185
+ previewText: string;
186
+ /** Byte range of this event's source line on disk; null when classified with no file context. */
187
+ ref: TranscriptEventRef | null;
178
188
  }
179
189
 
180
190
  export interface SubscribeResult {
@@ -396,7 +406,6 @@ export interface ScheduleConfig {
396
406
  /** Minutes to wait after the 5h reset before firing pending jobs.
397
407
  * Used by 'on-reset'. Ignored by 'when-available' and 'manual'. */
398
408
  offsetMinutes: number;
399
- concurrencyCap: number;
400
409
  defaultCwd: string;
401
410
  /** Auto-fire policy. Default 'when-available'. */
402
411
  firePolicy: ScheduleFirePolicy;
@@ -547,14 +556,45 @@ export interface SchedulePollHealth {
547
556
  lastFailureKind: string | null;
548
557
  }
549
558
 
559
+ /** One `pending` job held by an unsatisfied dependency, and which dep. */
560
+ export interface ScheduleJobHold {
561
+ slug: string;
562
+ dep: string;
563
+ depStatus: string;
564
+ }
565
+
566
+ /** Outcome of the scheduler's last tick — why the batch was (or wasn't) fired.
567
+ * Every field is computed by tickQueue; nothing here is derived in the UI. */
568
+ export interface ScheduleLastTick {
569
+ fired: boolean;
570
+ reason: 'held' | 'slots-exhausted' | 'memory-deferred' | 'already-running' | 'drained' | 'paused' | string;
571
+ /** Human-readable one-liner for the binding constraint, when there is one. */
572
+ detail?: string;
573
+ deferredCount?: number;
574
+ runningCount?: number;
575
+ count?: number;
576
+ availableMb?: number;
577
+ threshold?: number;
578
+ holders?: { owner: string; at: string }[];
579
+ holds?: ScheduleJobHold[];
580
+ at: string;
581
+ }
582
+
550
583
  export interface ScheduleEffectiveConcurrency {
584
+ /** Total slots in the machine-wide sessionSlots pool — the ONLY concurrency
585
+ * limit. The scheduler no longer carries a private concurrencyCap. */
551
586
  cap: number;
552
- /** 'env' when SM_SCHEDULER_MAX_CONCURRENCY pins the cap; 'config' when concurrencyCap governs. */
553
- source: 'env' | 'config';
587
+ /** Slots free right now (pool total minus held, incl. chat runs). */
588
+ free: number;
589
+ /** 'env' when SM_SESSION_SLOTS pins the pool; 'pool' when the persisted
590
+ * Home-tab value governs. */
591
+ source: 'env' | 'pool';
554
592
  }
555
593
 
556
594
  export interface ScheduleStateSnapshot {
557
595
  config: ScheduleConfig & { supervisor?: SupervisorConfig };
596
+ /** Why the last tick fired (or didn't). Null before the first tick. */
597
+ lastTick?: ScheduleLastTick | null;
558
598
  jobs: ScheduleJob[];
559
599
  scheduledFor: string | null;
560
600
  lastRunAt: string | null;
@@ -699,47 +739,6 @@ export interface FilesDuplicateResult { ok: boolean; path?: string; error?: stri
699
739
  export interface DocEditResult { ok: boolean; after?: string; error?: string }
700
740
  export interface DocEditSessionResult { tabId: string; requestId: string; ok: boolean; after?: string; error?: string }
701
741
 
702
- export interface SearchFileEntry {
703
- name: string;
704
- path: string;
705
- isDirectory: false;
706
- isFile: true;
707
- }
708
- export interface SearchFilesResult {
709
- ok: boolean;
710
- files: SearchFileEntry[];
711
- error: string | null;
712
- usedRipgrep: boolean;
713
- }
714
- export interface SearchTextMatch {
715
- path: string;
716
- line: number;
717
- column: number;
718
- text: string;
719
- }
720
- export interface SearchTextResult {
721
- ok: boolean;
722
- matches: SearchTextMatch[];
723
- error: string | null;
724
- usedRipgrep: boolean;
725
- }
726
-
727
- export interface RepoLanguageStats { files: number; lines: number }
728
- export interface RepoTopDirectory { path: string; fileCount: number; totalLines: number }
729
- export interface RepoGitStatusSummary { uncommitted: number; branch: string | null }
730
- export interface RepoAnalyzeResult {
731
- ok: true;
732
- cwd: string;
733
- totalFiles: number;
734
- totalLines: number;
735
- languageBreakdown: Record<string, RepoLanguageStats>;
736
- topDirectories: RepoTopDirectory[];
737
- gitStatus: RepoGitStatusSummary;
738
- truncated: boolean;
739
- durationMs: number;
740
- }
741
- export interface RepoAnalyzeError { ok: false; error: string }
742
-
743
742
  export interface WatcherInfo {
744
743
  watcherId: string;
745
744
  tabId: string;
@@ -989,17 +988,28 @@ export type ProjectBriefUpdateResult =
989
988
  | { ok: true; brief: ProjectBrief }
990
989
  | { ok: false; error: string };
991
990
 
992
- // ────────────────────────────────────────────── Project Pages (PRD 929-932)
991
+ // ────────────────────────────────────────────── Project Pages (PRD 929-932, 969, project-home-hosted-html-spec)
993
992
  export interface ProjectPagesOutput {
994
993
  home: string;
995
- marketing: string;
996
- feature: string;
997
- architecture: string;
998
- generatedAt: string;
994
+ /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
995
+ marketing?: string;
996
+ /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
997
+ feature?: string;
998
+ /** Absent when `isDefault` is true — the shipped default only covers the home lens. */
999
+ architecture?: string;
1000
+ /** Absent for output generated before the 'brief' lens existed (PRD 969), or
1001
+ * when `isDefault` is true — a project must regenerate to pick it up. */
1002
+ brief?: string;
1003
+ /** null for the shipped default (never generated). */
1004
+ generatedAt: string | null;
1005
+ /** True when `home` is the build-time shipped default, not this project's own
1006
+ * generated output — the renderer must label provenance rather than infer it. */
1007
+ isDefault: boolean;
999
1008
  }
1000
1009
 
1001
1010
  export interface ProjectPagesGetResult {
1002
- /** null when no manifest/output files exist yet — the empty-state signal. */
1011
+ /** Never null in practice — a project with no generated output still gets the
1012
+ * shipped default (isDefault: true). The type stays nullable defensively. */
1003
1013
  output: ProjectPagesOutput | null;
1004
1014
  }
1005
1015
 
@@ -1398,6 +1408,11 @@ export interface SessionManagerAPI {
1398
1408
  /** Permanently destroy the sub (genuine tab close). */
1399
1409
  closeTab: (tabId: string) => Promise<{ ok: boolean }>;
1400
1410
  buffer: (tabId: string) => Promise<TranscriptEvent[]>;
1411
+ /** Paged read over the subscribed transcript's line-offset index — [startLine, endLine] inclusive, 0-based.
1412
+ * Reads only the requested byte range from disk; never materializes the whole file. */
1413
+ page: (tabId: string, startLine: number, endLine: number) => Promise<{ events: (TranscriptEvent & { lineNumber: number })[]; totalLines: number }>;
1414
+ /** Full untruncated single-line read via a classifier byte reference (expand-to-full path). */
1415
+ readRef: (ref: TranscriptEventRef) => Promise<{ ok: boolean; text?: string; error?: string }>;
1401
1416
  pathFor: (cwd: string, sessionUuid: string) => Promise<string>;
1402
1417
  /** Batched token-usage totals, one map entry per requested sessionId. A
1403
1418
  * session with no transcript file yet (or one over the main-process size
@@ -1521,13 +1536,6 @@ export interface SessionManagerAPI {
1521
1536
  | { as: 'revealPath'; path: string }
1522
1537
  ) => Promise<{ ok: boolean; opener?: string; error?: string }>;
1523
1538
  };
1524
- search: {
1525
- files: (cwd: string, query?: string, opts?: { limit?: number }) => Promise<SearchFilesResult>;
1526
- text: (cwd: string, query: string, opts?: { limit?: number; caseSensitive?: boolean }) => Promise<SearchTextResult>;
1527
- };
1528
- repo: {
1529
- analyze: (cwd: string) => Promise<RepoAnalyzeResult | RepoAnalyzeError>;
1530
- };
1531
1539
  history: {
1532
1540
  aggregate: (req?: HistoryAggregateRequest) => Promise<HistoryAggregateResult>;
1533
1541
  scanProjects: () => Promise<SessionScanResult>;
@@ -1765,6 +1773,12 @@ export interface SessionManagerAPI {
1765
1773
  * in-memory contribution for the cwd; disk stays main's truth, merged
1766
1774
  * inside the same lock epicMint.cjs's ensureEpic serializes through. */
1767
1775
  mergeActiveIndex: (payload: PromptSessionsMergeActiveIndexPayload) => Promise<PromptSessionsMergeActiveIndexResult>;
1776
+ /** Mints a brand-new 'proposed' Epic through main's own ensureEpic()
1777
+ * (lib/promptSessionsCreateEpic.cjs) instead of the renderer
1778
+ * hand-constructing the PromptSession record itself. Unused today —
1779
+ * additive step 1 of a two-PRD chain; a later PRD routes
1780
+ * createPromptSession through this. */
1781
+ create: (payload: PromptSessionsCreateEpicPayload) => Promise<PromptSessionsCreateEpicResult>;
1768
1782
  };
1769
1783
  }
1770
1784
 
@@ -1782,6 +1796,35 @@ export interface PromptSessionsMergeActiveIndexResult {
1782
1796
  events: Record<string, unknown[]>;
1783
1797
  }
1784
1798
 
1799
+ // ─────────────────────────────────── PromptSessions create-epic (main-side ensureEpic)
1800
+ export interface PromptSessionsCreateEpicPayload {
1801
+ cwd: string;
1802
+ goalText: string;
1803
+ tag?: 'feature' | 'bug' | 'discussion' | 'build' | 'project-home-builder' | 'bilko-host-publisher';
1804
+ agentType?: string;
1805
+ source?: {
1806
+ producer: 'new-epic-ui' | 'scheduler-dispatch';
1807
+ prdSlug?: string;
1808
+ runId?: string;
1809
+ sourceTabId?: string;
1810
+ };
1811
+ /** Full first-prompt body + its labeled sections (epicIntake.ts's
1812
+ * composeEpicIntake) — carried alongside goalText so the Epic's first
1813
+ * turn can render a structured AIM briefing card. */
1814
+ openingPrompt?: string;
1815
+ sections?: Array<{
1816
+ kind: 'actor' | 'injection' | 'input' | 'mission' | 'goal' | 'reference';
1817
+ label: string;
1818
+ text: string;
1819
+ source?: string;
1820
+ }>;
1821
+ }
1822
+
1823
+ export interface PromptSessionsCreateEpicResult {
1824
+ epicId: string;
1825
+ session: Record<string, unknown>;
1826
+ }
1827
+
1785
1828
  // ─────────────────────────────────── PromptSession event-appended broadcast
1786
1829
 
1787
1830
  export interface PromptSessionEventAppendedPayload {
@@ -121,6 +121,9 @@ contextBridge.exposeInMainWorld('api', {
121
121
  unsubscribe: (tabId) => ipcRenderer.invoke('transcript:unsubscribe', { tabId }),
122
122
  closeTab: (tabId) => ipcRenderer.invoke('transcript:close', { tabId }),
123
123
  buffer: (tabId) => ipcRenderer.invoke('transcript:buffer', { tabId }),
124
+ page: (tabId, startLine, endLine) =>
125
+ ipcRenderer.invoke('transcript:page', { tabId, startLine, endLine }),
126
+ readRef: (ref) => ipcRenderer.invoke('transcript:readRef', ref),
124
127
  pathFor: (cwd, sessionUuid) =>
125
128
  ipcRenderer.invoke('transcript:path', { cwd, sessionUuid }),
126
129
  usageFor: (cwd, sessionIds) =>
@@ -258,13 +261,6 @@ contextBridge.exposeInMainWorld('api', {
258
261
  shell: {
259
262
  open: (opts) => ipcRenderer.invoke('shell:open', opts),
260
263
  },
261
- search: {
262
- files: (cwd, query, opts) => ipcRenderer.invoke('search:files', { cwd, query, opts }),
263
- text: (cwd, query, opts) => ipcRenderer.invoke('search:text', { cwd, query, opts }),
264
- },
265
- repo: {
266
- analyze: (cwd) => ipcRenderer.invoke('repo:analyze', { cwd }),
267
- },
268
264
  schedule: {
269
265
  state: () => ipcRenderer.invoke('schedule:state'),
270
266
  sessionSlots: () => ipcRenderer.invoke('schedule:session-slots'),
@@ -493,5 +489,11 @@ contextBridge.exposeInMainWorld('api', {
493
489
  * renderer-side read-merge-write. Payload carries only this renderer's
494
490
  * own in-memory contribution for the cwd; disk stays main's truth. */
495
491
  mergeActiveIndex: (payload) => ipcRenderer.invoke('promptSessions:merge-active-index', payload),
492
+ /** Mints a brand-new 'proposed' Epic through main's own ensureEpic()
493
+ * (lib/promptSessionsCreateEpic.cjs) instead of the renderer
494
+ * hand-constructing the PromptSession record itself. Unused today —
495
+ * additive step 1 of a two-PRD chain; a later PRD routes
496
+ * createPromptSession through this. */
497
+ create: (payload) => ipcRenderer.invoke('promptSessions:create-epic', payload),
496
498
  },
497
499
  });