@ulpi/cli 0.1.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 (92) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/dist/auth-PN7TMQHV-2W4ICG64.js +15 -0
  4. package/dist/chunk-247GVVKK.js +2259 -0
  5. package/dist/chunk-2CLNOKPA.js +793 -0
  6. package/dist/chunk-2HEE5OKX.js +79 -0
  7. package/dist/chunk-2MZER6ND.js +415 -0
  8. package/dist/chunk-3SBPZRB5.js +772 -0
  9. package/dist/chunk-4VNS5WPM.js +42 -0
  10. package/dist/chunk-6JCMYYBT.js +1546 -0
  11. package/dist/chunk-6OCEY7JY.js +422 -0
  12. package/dist/chunk-74WVVWJ4.js +375 -0
  13. package/dist/chunk-7AL4DOEJ.js +131 -0
  14. package/dist/chunk-7LXY5UVC.js +330 -0
  15. package/dist/chunk-DBMUNBNB.js +3048 -0
  16. package/dist/chunk-JWUUVXIV.js +13694 -0
  17. package/dist/chunk-KIKPIH6N.js +4048 -0
  18. package/dist/chunk-KLEASXUR.js +70 -0
  19. package/dist/chunk-MIAQVCFW.js +39 -0
  20. package/dist/chunk-NNUWU6CV.js +1610 -0
  21. package/dist/chunk-PKD4ASEM.js +115 -0
  22. package/dist/chunk-Q4HIY43N.js +4230 -0
  23. package/dist/chunk-QJ5GSMEC.js +146 -0
  24. package/dist/chunk-SIAQVRKG.js +2163 -0
  25. package/dist/chunk-SPOI23SB.js +197 -0
  26. package/dist/chunk-YM2HV4IA.js +505 -0
  27. package/dist/codemap-RRJIDBQ5.js +636 -0
  28. package/dist/config-EGAXXCGL.js +127 -0
  29. package/dist/dist-6G7JC2RA.js +90 -0
  30. package/dist/dist-7LHZ65GC.js +418 -0
  31. package/dist/dist-LZKZFPVX.js +140 -0
  32. package/dist/dist-R5F4MX3I.js +107 -0
  33. package/dist/dist-R5ZJ4LX5.js +56 -0
  34. package/dist/dist-RJGCUS3L.js +87 -0
  35. package/dist/dist-RKOGLK7R.js +151 -0
  36. package/dist/dist-W7K4WPAF.js +597 -0
  37. package/dist/export-import-4A5MWLIA.js +53 -0
  38. package/dist/history-ATTUKOHO.js +934 -0
  39. package/dist/index.js +2120 -0
  40. package/dist/init-AY5C2ZAS.js +393 -0
  41. package/dist/launchd-LF2QMSKZ.js +148 -0
  42. package/dist/log-TVTUXAYD.js +75 -0
  43. package/dist/mcp-installer-NQCGKQ23.js +124 -0
  44. package/dist/memory-J3G24QHS.js +406 -0
  45. package/dist/ollama-3XCUZMZT-FYKHW4TZ.js +7 -0
  46. package/dist/openai-E7G2YAHU-UYY4ZWON.js +8 -0
  47. package/dist/projects-ATHDD3D6.js +271 -0
  48. package/dist/review-ADUPV3PN.js +152 -0
  49. package/dist/rules-E427DKYJ.js +134 -0
  50. package/dist/server-MOYPE4SM-N7SE2AN7.js +18 -0
  51. package/dist/server-X5P6WH2M-7K2RY34N.js +11 -0
  52. package/dist/skills/ulpi-generate-guardian/SKILL.md +511 -0
  53. package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +692 -0
  54. package/dist/skills/ulpi-generate-guardian/references/language-rules.md +596 -0
  55. package/dist/skills-CX73O3IV.js +76 -0
  56. package/dist/status-4DFHDJMN.js +66 -0
  57. package/dist/templates/biome.yml +24 -0
  58. package/dist/templates/conventional-commits.yml +18 -0
  59. package/dist/templates/django.yml +30 -0
  60. package/dist/templates/docker.yml +30 -0
  61. package/dist/templates/eslint.yml +13 -0
  62. package/dist/templates/express.yml +20 -0
  63. package/dist/templates/fastapi.yml +23 -0
  64. package/dist/templates/git-flow.yml +26 -0
  65. package/dist/templates/github-flow.yml +27 -0
  66. package/dist/templates/go.yml +33 -0
  67. package/dist/templates/jest.yml +24 -0
  68. package/dist/templates/laravel.yml +30 -0
  69. package/dist/templates/monorepo.yml +26 -0
  70. package/dist/templates/nestjs.yml +21 -0
  71. package/dist/templates/nextjs.yml +31 -0
  72. package/dist/templates/nodejs.yml +33 -0
  73. package/dist/templates/npm.yml +15 -0
  74. package/dist/templates/php.yml +25 -0
  75. package/dist/templates/pnpm.yml +15 -0
  76. package/dist/templates/prettier.yml +23 -0
  77. package/dist/templates/prisma.yml +21 -0
  78. package/dist/templates/python.yml +33 -0
  79. package/dist/templates/quality-of-life.yml +111 -0
  80. package/dist/templates/ruby.yml +25 -0
  81. package/dist/templates/rust.yml +34 -0
  82. package/dist/templates/typescript.yml +14 -0
  83. package/dist/templates/vitest.yml +24 -0
  84. package/dist/templates/yarn.yml +15 -0
  85. package/dist/templates-U7T6MARD.js +156 -0
  86. package/dist/ui-L7UAWXDY.js +167 -0
  87. package/dist/ui.html +698 -0
  88. package/dist/ulpi-RMMCUAGP-JCJ273T6.js +161 -0
  89. package/dist/uninstall-6SW35IK4.js +25 -0
  90. package/dist/update-M2B4RLGH.js +61 -0
  91. package/dist/version-checker-ANCS3IHR.js +10 -0
  92. package/package.json +92 -0
@@ -0,0 +1,375 @@
1
+ import {
2
+ external_exports
3
+ } from "./chunk-KIKPIH6N.js";
4
+
5
+ // ../../packages/contracts/dist/index.js
6
+ var BlockTypeSchema = external_exports.enum([
7
+ "heading",
8
+ "paragraph",
9
+ "code",
10
+ "list-item",
11
+ "blockquote",
12
+ "table",
13
+ "hr"
14
+ ]);
15
+ var BlockSchema = external_exports.object({
16
+ id: external_exports.string().max(200),
17
+ type: BlockTypeSchema,
18
+ content: external_exports.string().max(1e5),
19
+ level: external_exports.number().optional(),
20
+ language: external_exports.string().max(100).optional(),
21
+ checked: external_exports.boolean().optional(),
22
+ order: external_exports.number().int(),
23
+ startLine: external_exports.number().int()
24
+ });
25
+ var SectionStatusSchema = external_exports.enum([
26
+ "pending",
27
+ "in_progress",
28
+ "completed",
29
+ "skipped"
30
+ ]);
31
+ var PlanSectionSchema = external_exports.object({
32
+ id: external_exports.string().max(200),
33
+ blockIds: external_exports.array(external_exports.string().max(200)),
34
+ title: external_exports.string().max(1e3),
35
+ level: external_exports.number().int().min(0).max(6),
36
+ path: external_exports.string().max(2e3),
37
+ status: SectionStatusSchema,
38
+ order: external_exports.number().int()
39
+ });
40
+ var PriorityLevelSchema = external_exports.enum([
41
+ "must-have",
42
+ "should-have",
43
+ "nice-to-have",
44
+ "out-of-scope"
45
+ ]);
46
+ var SectionPrioritySchema = external_exports.object({
47
+ sectionId: external_exports.string().max(200),
48
+ priority: PriorityLevelSchema,
49
+ note: external_exports.string().max(5e3).optional()
50
+ });
51
+ var RiskLevelSchema = external_exports.enum(["low", "medium", "high"]);
52
+ var SectionRiskSchema = external_exports.object({
53
+ sectionId: external_exports.string().max(200),
54
+ level: RiskLevelSchema,
55
+ description: external_exports.string().max(1e4)
56
+ });
57
+ var SectionInstructionSchema = external_exports.object({
58
+ id: external_exports.string().max(200),
59
+ sectionId: external_exports.string().max(200),
60
+ instruction: external_exports.string().max(1e4),
61
+ priority: external_exports.enum(["must", "should", "nice-to-have"]).optional(),
62
+ createdAt: external_exports.number(),
63
+ author: external_exports.string().max(200).optional()
64
+ });
65
+ var AnnotationTypeSchema = external_exports.enum([
66
+ "comment",
67
+ "suggestion",
68
+ "concern",
69
+ "question",
70
+ "approval",
71
+ "instruction",
72
+ "global_comment"
73
+ ]);
74
+ var ReviewAnnotationSchema = external_exports.object({
75
+ id: external_exports.string().max(200),
76
+ type: AnnotationTypeSchema,
77
+ blockId: external_exports.string().max(200),
78
+ sectionId: external_exports.string().max(200).optional(),
79
+ startOffset: external_exports.number().optional(),
80
+ endOffset: external_exports.number().optional(),
81
+ originalText: external_exports.string().max(5e4),
82
+ text: external_exports.string().max(5e4),
83
+ author: external_exports.string().max(200).optional(),
84
+ authorColor: external_exports.string().max(50).optional(),
85
+ resolved: external_exports.boolean().optional(),
86
+ createdAt: external_exports.number(),
87
+ imagePaths: external_exports.array(external_exports.string().max(500)).optional()
88
+ });
89
+ var ANNOTATION_TYPE_LABELS = {
90
+ comment: "Comment",
91
+ suggestion: "Suggestion",
92
+ concern: "Concern",
93
+ question: "Question",
94
+ approval: "Approved",
95
+ instruction: "Instruction",
96
+ global_comment: "Global Comment"
97
+ };
98
+ var ANNOTATION_TYPE_FEEDBACK_PREFIX = {
99
+ comment: "COMMENT",
100
+ suggestion: "SUGGESTION",
101
+ concern: "CONCERN",
102
+ question: "QUESTION",
103
+ approval: "APPROVAL",
104
+ instruction: "INSTRUCTION",
105
+ global_comment: "GLOBAL"
106
+ };
107
+ var DiffChunkTypeSchema = external_exports.enum(["equal", "insert", "delete"]);
108
+ var DiffChunkSchema = external_exports.object({
109
+ type: DiffChunkTypeSchema,
110
+ value: external_exports.string().max(5e5)
111
+ });
112
+ var InlineEditSchema = external_exports.object({
113
+ id: external_exports.string().max(200),
114
+ blockId: external_exports.string().max(200),
115
+ sectionId: external_exports.string().max(200).optional(),
116
+ originalContent: external_exports.string().max(1e5),
117
+ editedContent: external_exports.string().max(1e5),
118
+ characterDiff: external_exports.array(DiffChunkSchema),
119
+ author: external_exports.string().max(200).optional(),
120
+ createdAt: external_exports.number()
121
+ });
122
+ var ReviewDecisionSchema = external_exports.object({
123
+ behavior: external_exports.enum(["allow", "deny"]),
124
+ message: external_exports.string().max(1e4).optional(),
125
+ decidedAt: external_exports.number()
126
+ });
127
+ var RepoInfoSchema = external_exports.object({
128
+ remote: external_exports.string().max(2e3).optional(),
129
+ branch: external_exports.string().max(500).optional(),
130
+ display: external_exports.string().max(500).optional()
131
+ });
132
+ var PlanStatusSchema = external_exports.enum([
133
+ "reviewing",
134
+ "approved",
135
+ "denied",
136
+ "executing",
137
+ "completed"
138
+ ]);
139
+ var CodemapEmbeddingProviderSchema = external_exports.enum(["openai", "ollama", "ulpi"]);
140
+ var CodemapEmbeddingConfigSchema = external_exports.object({
141
+ provider: CodemapEmbeddingProviderSchema.default("ulpi"),
142
+ model: external_exports.string().max(100).default("code"),
143
+ dimensions: external_exports.number().int().positive().max(4096).default(1024),
144
+ baseUrl: external_exports.string().url().max(200).optional()
145
+ });
146
+ var CodemapChunkingStrategySchema = external_exports.enum(["sliding-window", "ast"]);
147
+ var CodemapChunkingConfigSchema = external_exports.object({
148
+ strategy: CodemapChunkingStrategySchema.default("ast"),
149
+ windowSize: external_exports.number().int().positive().max(500).default(60),
150
+ overlap: external_exports.number().int().nonnegative().max(100).default(10),
151
+ maxChunkSize: external_exports.number().int().positive().max(1e3).default(300),
152
+ minChunkSize: external_exports.number().int().positive().max(50).default(5),
153
+ contextLines: external_exports.number().int().nonnegative().max(20).default(3),
154
+ version: external_exports.number().int().positive().default(2)
155
+ });
156
+ var CodemapBatchConfigSchema = external_exports.object({
157
+ size: external_exports.number().int().positive().max(1e4).default(1e4),
158
+ debounceMs: external_exports.number().int().nonnegative().max(3e4).default(500),
159
+ timeoutMs: external_exports.number().int().nonnegative().max(36e5).default(6e5),
160
+ // 0 = no timeout
161
+ pollIntervalMs: external_exports.number().int().positive().max(6e4).default(2e3)
162
+ // 2s
163
+ });
164
+ var CodemapHybridWeightsSchema = external_exports.object({
165
+ vector: external_exports.number().min(0).max(1).default(0.6),
166
+ bm25: external_exports.number().min(0).max(1).default(0.25),
167
+ symbolBoost: external_exports.number().min(0).max(1).default(0.1),
168
+ pathBoost: external_exports.number().min(0).max(1).default(0.05),
169
+ graphRank: external_exports.number().min(0).max(1).default(0)
170
+ });
171
+ var CodemapHybridConfigSchema = external_exports.object({
172
+ enabled: external_exports.boolean().default(true),
173
+ vectorK: external_exports.number().int().positive().max(200).default(30),
174
+ bm25K: external_exports.number().int().positive().max(200).default(30),
175
+ weights: CodemapHybridWeightsSchema.default({})
176
+ });
177
+ var CodemapConfigSchema = external_exports.object({
178
+ embedding: CodemapEmbeddingConfigSchema.default({}),
179
+ chunking: CodemapChunkingConfigSchema.default({}),
180
+ batch: CodemapBatchConfigSchema.default({}),
181
+ hybrid: CodemapHybridConfigSchema.default({}),
182
+ deny: external_exports.array(external_exports.string().max(500)).max(200).default(["**/.env*", "**/secrets/**", "**/certs/**"]),
183
+ maxFileSize: external_exports.number().int().positive().default(1048576),
184
+ // 1MB
185
+ autoExport: external_exports.boolean().default(true),
186
+ // Export to shadow branch on push / session-end
187
+ autoImport: external_exports.boolean().default(true)
188
+ // Import from shadow branch on session-start
189
+ });
190
+ var CodemapSymbolTypeSchema = external_exports.enum([
191
+ "function",
192
+ "class",
193
+ "method",
194
+ "interface",
195
+ "type",
196
+ "const",
197
+ "variable",
198
+ "enum",
199
+ "unknown"
200
+ ]);
201
+ var MemoryTypeSchema = external_exports.enum([
202
+ "DECISION",
203
+ // Architecture/design decisions with rationale
204
+ "PATTERN",
205
+ // Code patterns adopted or enforced
206
+ "BUG_ROOT_CAUSE",
207
+ // Root causes of bugs discovered
208
+ "PREFERENCE",
209
+ // User preferences (style, tools, workflow)
210
+ "CONSTRAINT",
211
+ // Project constraints (perf budgets, compat)
212
+ "CONTEXT",
213
+ // Domain knowledge, terminology, relationships
214
+ "LESSON",
215
+ // Lessons learned from mistakes
216
+ "RELATIONSHIP"
217
+ // Inter-component relationships
218
+ ]);
219
+ var MemoryImportanceSchema = external_exports.enum([
220
+ "critical",
221
+ // Never decay, always surface
222
+ "high",
223
+ // Slow decay
224
+ "medium",
225
+ // Moderate decay
226
+ "low"
227
+ // Fast decay
228
+ ]);
229
+ var CaptureModeSchema = external_exports.enum([
230
+ "continuous",
231
+ // Append events via post-tool hook during session
232
+ "end_of_session"
233
+ // Bulk-capture from session-engine JSONL at session-end
234
+ ]);
235
+ var MemorySourceSchema = external_exports.object({
236
+ type: external_exports.enum(["explicit", "classifier", "import"]),
237
+ sessionId: external_exports.string().max(200).optional(),
238
+ author: external_exports.string().max(100).optional()
239
+ });
240
+ var MemoryEntrySchema = external_exports.object({
241
+ id: external_exports.string().max(64),
242
+ // SHA-256 hash of type + content
243
+ type: MemoryTypeSchema,
244
+ summary: external_exports.string().max(2e3),
245
+ // The memory text
246
+ detail: external_exports.string().max(1e4).nullable().default(null),
247
+ importance: MemoryImportanceSchema.default("medium"),
248
+ tags: external_exports.array(external_exports.string().max(50)).max(20).default([]),
249
+ relatedFiles: external_exports.array(external_exports.string().max(500)).max(50).default([]),
250
+ source: MemorySourceSchema,
251
+ createdAt: external_exports.string(),
252
+ // ISO timestamp
253
+ updatedAt: external_exports.string(),
254
+ // ISO timestamp (for reinforcement)
255
+ accessCount: external_exports.number().int().nonnegative().default(0),
256
+ lastAccessedAt: external_exports.string().optional(),
257
+ supersededBy: external_exports.string().max(64).optional()
258
+ });
259
+ var MemoryEmbeddingConfigSchema = external_exports.object({
260
+ provider: external_exports.enum(["openai", "ollama", "ulpi"]).default("ulpi"),
261
+ model: external_exports.string().max(100).default("code"),
262
+ dimensions: external_exports.number().int().positive().max(4096).default(1024),
263
+ baseUrl: external_exports.string().url().max(200).optional()
264
+ });
265
+ var MemoryClassifierConfigSchema = external_exports.object({
266
+ enabled: external_exports.boolean().default(true),
267
+ model: external_exports.string().max(100).default("claude-sonnet-4-20250514"),
268
+ windowSize: external_exports.number().int().positive().max(200).default(50),
269
+ windowOverlap: external_exports.number().int().nonnegative().max(50).default(10),
270
+ maxTranscriptChars: external_exports.number().int().positive().default(1e4),
271
+ timeout: external_exports.number().int().positive().default(12e4),
272
+ includeTranscript: external_exports.boolean().default(true),
273
+ maxSinglePromptEvents: external_exports.number().int().positive().max(500).default(100),
274
+ minSignificantEvents: external_exports.number().int().nonnegative().max(50).default(5),
275
+ filterNoiseEvents: external_exports.boolean().default(true)
276
+ });
277
+ var MemoryRetentionConfigSchema = external_exports.object({
278
+ maxMemories: external_exports.number().int().positive().max(1e4).default(5e3),
279
+ maxAgeDays: external_exports.number().int().positive().default(365),
280
+ deduplicationThreshold: external_exports.number().min(0).max(1).default(0.92)
281
+ });
282
+ var MemoryRankingConfigSchema = external_exports.object({
283
+ importanceWeights: external_exports.object({
284
+ critical: external_exports.number().min(0).max(1).default(1),
285
+ high: external_exports.number().min(0).max(1).default(0.8),
286
+ medium: external_exports.number().min(0).max(1).default(0.6),
287
+ low: external_exports.number().min(0).max(1).default(0.4)
288
+ }).default({}),
289
+ accessBoostPerHit: external_exports.number().min(0).max(0.1).default(0.05),
290
+ accessBoostCap: external_exports.number().min(0).max(1).default(0.2)
291
+ });
292
+ var MemoryConfigSchema = external_exports.object({
293
+ enabled: external_exports.boolean().default(false),
294
+ captureMode: CaptureModeSchema.default("continuous"),
295
+ surfaceOnStart: external_exports.boolean().default(true),
296
+ surfaceLimit: external_exports.number().int().positive().max(20).default(5),
297
+ embedding: MemoryEmbeddingConfigSchema.default({}),
298
+ classifier: MemoryClassifierConfigSchema.default({}),
299
+ retention: MemoryRetentionConfigSchema.default({}),
300
+ ranking: MemoryRankingConfigSchema.default({}),
301
+ redactPatterns: external_exports.array(external_exports.string().max(500)).max(50).default([]),
302
+ autoExport: external_exports.boolean().default(false)
303
+ });
304
+ var ClassificationResultSchema = external_exports.object({
305
+ memories: external_exports.array(external_exports.object({
306
+ type: MemoryTypeSchema,
307
+ summary: external_exports.string().max(2e3),
308
+ detail: external_exports.string().max(1e4).optional(),
309
+ importance: MemoryImportanceSchema.default("medium"),
310
+ tags: external_exports.array(external_exports.string().max(50)).max(20).default([]),
311
+ relatedFiles: external_exports.array(external_exports.string().max(500)).max(50).default([])
312
+ })).max(20)
313
+ });
314
+ var DepgraphPersonalizationConfigSchema = external_exports.object({
315
+ activeFileBoost: external_exports.number().positive().default(100),
316
+ mentionedFileBoost: external_exports.number().positive().default(5),
317
+ mentionedIdentifierBoost: external_exports.number().positive().default(10)
318
+ });
319
+ var DepgraphPagerankConfigSchema = external_exports.object({
320
+ dampingFactor: external_exports.number().min(0).max(1).default(0.85),
321
+ maxIterations: external_exports.number().int().positive().max(1e4).default(100),
322
+ convergenceThreshold: external_exports.number().positive().default(1e-6)
323
+ });
324
+ var DepgraphConfigSchema = external_exports.object({
325
+ enabled: external_exports.boolean().default(true),
326
+ personalization: DepgraphPersonalizationConfigSchema.default({}),
327
+ pagerank: DepgraphPagerankConfigSchema.default({}),
328
+ excludeUnranked: external_exports.boolean().default(false),
329
+ excludeUnrankedThreshold: external_exports.number().nonnegative().default(1e-4)
330
+ });
331
+
332
+ export {
333
+ BlockTypeSchema,
334
+ BlockSchema,
335
+ SectionStatusSchema,
336
+ PlanSectionSchema,
337
+ PriorityLevelSchema,
338
+ SectionPrioritySchema,
339
+ RiskLevelSchema,
340
+ SectionRiskSchema,
341
+ SectionInstructionSchema,
342
+ AnnotationTypeSchema,
343
+ ReviewAnnotationSchema,
344
+ ANNOTATION_TYPE_LABELS,
345
+ ANNOTATION_TYPE_FEEDBACK_PREFIX,
346
+ DiffChunkTypeSchema,
347
+ DiffChunkSchema,
348
+ InlineEditSchema,
349
+ ReviewDecisionSchema,
350
+ RepoInfoSchema,
351
+ PlanStatusSchema,
352
+ CodemapEmbeddingProviderSchema,
353
+ CodemapEmbeddingConfigSchema,
354
+ CodemapChunkingStrategySchema,
355
+ CodemapChunkingConfigSchema,
356
+ CodemapBatchConfigSchema,
357
+ CodemapHybridWeightsSchema,
358
+ CodemapHybridConfigSchema,
359
+ CodemapConfigSchema,
360
+ CodemapSymbolTypeSchema,
361
+ MemoryTypeSchema,
362
+ MemoryImportanceSchema,
363
+ CaptureModeSchema,
364
+ MemorySourceSchema,
365
+ MemoryEntrySchema,
366
+ MemoryEmbeddingConfigSchema,
367
+ MemoryClassifierConfigSchema,
368
+ MemoryRetentionConfigSchema,
369
+ MemoryRankingConfigSchema,
370
+ MemoryConfigSchema,
371
+ ClassificationResultSchema,
372
+ DepgraphPersonalizationConfigSchema,
373
+ DepgraphPagerankConfigSchema,
374
+ DepgraphConfigSchema
375
+ };
@@ -0,0 +1,131 @@
1
+ import {
2
+ getApiSecret
3
+ } from "./chunk-MIAQVCFW.js";
4
+ import {
5
+ getProject
6
+ } from "./chunk-SPOI23SB.js";
7
+ import {
8
+ JsonSessionStore,
9
+ readEvents
10
+ } from "./chunk-YM2HV4IA.js";
11
+ import {
12
+ getApiHost
13
+ } from "./chunk-7LXY5UVC.js";
14
+
15
+ // ../api/dist/chunk-F3LN44RE.js
16
+ import { WebSocketServer } from "ws";
17
+ function attachWebSocket(server, defaultProjectDir) {
18
+ const wss = new WebSocketServer({
19
+ server,
20
+ path: "/ws",
21
+ verifyClient: ({ req }, cb) => {
22
+ const remoteAddr = req.socket.remoteAddress ?? "";
23
+ const isLoopback = remoteAddr === "127.0.0.1" || remoteAddr === "::1" || remoteAddr === "::ffff:127.0.0.1";
24
+ if (!isLoopback) {
25
+ cb(false, 403, "Forbidden: only local connections allowed");
26
+ return;
27
+ }
28
+ const secret = getApiSecret();
29
+ if (secret) {
30
+ try {
31
+ const wsUrl = new URL(req.url ?? "/", `http://${req.headers.host}`);
32
+ const reqSecret = wsUrl.searchParams.get("secret");
33
+ if (reqSecret !== secret) {
34
+ cb(false, 403, "Forbidden: invalid API secret");
35
+ return;
36
+ }
37
+ } catch {
38
+ cb(false, 403, "Forbidden: invalid request URL");
39
+ return;
40
+ }
41
+ }
42
+ const origin = req.headers.origin;
43
+ if (origin) {
44
+ let originHostname;
45
+ let originProtocol;
46
+ try {
47
+ const parsed = new URL(origin);
48
+ originHostname = parsed.hostname;
49
+ originProtocol = parsed.protocol;
50
+ } catch {
51
+ cb(false, 403, "Forbidden: malformed origin");
52
+ return;
53
+ }
54
+ if (originProtocol !== "http:") {
55
+ cb(false, 403, "Forbidden: origin not allowed");
56
+ return;
57
+ }
58
+ const allowedHostnames = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", getApiHost()]);
59
+ if (!allowedHostnames.has(originHostname)) {
60
+ cb(false, 403, "Forbidden: origin not allowed");
61
+ return;
62
+ }
63
+ }
64
+ cb(true);
65
+ }
66
+ });
67
+ wss.on("connection", (ws, req) => {
68
+ let lastSessionJson = "";
69
+ let lastEventCount = 0;
70
+ let lastSessionId = "";
71
+ let projectDir = defaultProjectDir;
72
+ let pinnedSessionId = null;
73
+ if (req.url) {
74
+ try {
75
+ const url = new URL(req.url, `http://${req.headers.host}`);
76
+ const projectParam = url.searchParams.get("project");
77
+ if (projectParam) {
78
+ const entry = getProject(projectParam);
79
+ if (entry) {
80
+ projectDir = entry.path;
81
+ }
82
+ }
83
+ pinnedSessionId = url.searchParams.get("session");
84
+ } catch {
85
+ }
86
+ }
87
+ const store = new JsonSessionStore(void 0, projectDir);
88
+ const poll = setInterval(() => {
89
+ try {
90
+ let state;
91
+ if (pinnedSessionId) {
92
+ state = store.load(pinnedSessionId);
93
+ } else {
94
+ state = store.getLatestForProject(projectDir);
95
+ }
96
+ if (!state) return;
97
+ const currentSessionId = state.sessionId;
98
+ if (currentSessionId !== lastSessionId) {
99
+ lastSessionId = currentSessionId;
100
+ lastEventCount = 0;
101
+ lastSessionJson = "";
102
+ }
103
+ const stateJson = JSON.stringify(state);
104
+ if (stateJson !== lastSessionJson) {
105
+ lastSessionJson = stateJson;
106
+ ws.send(JSON.stringify({ type: "session-update", data: state }));
107
+ }
108
+ const events = readEvents(currentSessionId, projectDir);
109
+ if (events.length > lastEventCount) {
110
+ const newEvents = events.slice(lastEventCount);
111
+ for (const event of newEvents) {
112
+ ws.send(JSON.stringify({ type: "event", data: event }));
113
+ }
114
+ lastEventCount = events.length;
115
+ }
116
+ } catch {
117
+ }
118
+ }, 2e3);
119
+ ws.on("close", () => {
120
+ clearInterval(poll);
121
+ });
122
+ ws.on("error", () => {
123
+ clearInterval(poll);
124
+ });
125
+ });
126
+ return wss;
127
+ }
128
+
129
+ export {
130
+ attachWebSocket
131
+ };