veryfront 0.0.81 → 0.0.83

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 (157) hide show
  1. package/README.md +15 -1
  2. package/esm/deno.js +1 -1
  3. package/esm/proxy/cache/index.d.ts +41 -0
  4. package/esm/proxy/cache/index.d.ts.map +1 -0
  5. package/esm/proxy/cache/index.js +75 -0
  6. package/esm/proxy/cache/memory-cache.d.ts +18 -0
  7. package/esm/proxy/cache/memory-cache.d.ts.map +1 -0
  8. package/esm/proxy/cache/memory-cache.js +100 -0
  9. package/esm/proxy/cache/redis-cache.d.ts +27 -0
  10. package/esm/proxy/cache/redis-cache.d.ts.map +1 -0
  11. package/esm/proxy/cache/redis-cache.js +183 -0
  12. package/esm/proxy/cache/resilient-cache.d.ts +44 -0
  13. package/esm/proxy/cache/resilient-cache.d.ts.map +1 -0
  14. package/esm/proxy/cache/resilient-cache.js +178 -0
  15. package/esm/proxy/cache/types.d.ts +65 -0
  16. package/esm/proxy/cache/types.d.ts.map +1 -0
  17. package/esm/proxy/cache/types.js +7 -0
  18. package/esm/proxy/handler.d.ts +81 -0
  19. package/esm/proxy/handler.d.ts.map +1 -0
  20. package/esm/proxy/handler.js +417 -0
  21. package/esm/proxy/logger.d.ts +29 -0
  22. package/esm/proxy/logger.d.ts.map +1 -0
  23. package/esm/proxy/logger.js +258 -0
  24. package/esm/proxy/oauth-client.d.ts +15 -0
  25. package/esm/proxy/oauth-client.d.ts.map +1 -0
  26. package/esm/proxy/oauth-client.js +52 -0
  27. package/esm/proxy/token-manager.d.ts +59 -0
  28. package/esm/proxy/token-manager.d.ts.map +1 -0
  29. package/esm/proxy/token-manager.js +125 -0
  30. package/esm/proxy/tracing.d.ts +39 -0
  31. package/esm/proxy/tracing.d.ts.map +1 -0
  32. package/esm/proxy/tracing.js +194 -0
  33. package/esm/src/cache/backend.d.ts +22 -0
  34. package/esm/src/cache/backend.d.ts.map +1 -1
  35. package/esm/src/cache/backend.js +59 -0
  36. package/esm/src/cache/cache-key-builder.d.ts +0 -4
  37. package/esm/src/cache/cache-key-builder.d.ts.map +1 -1
  38. package/esm/src/cache/cache-key-builder.js +0 -6
  39. package/esm/src/cache/hash.d.ts +107 -0
  40. package/esm/src/cache/hash.d.ts.map +1 -0
  41. package/esm/src/cache/hash.js +166 -0
  42. package/esm/src/cache/index.d.ts +3 -0
  43. package/esm/src/cache/index.d.ts.map +1 -1
  44. package/esm/src/cache/index.js +3 -0
  45. package/esm/src/cache/module-cache.d.ts +82 -0
  46. package/esm/src/cache/module-cache.d.ts.map +1 -0
  47. package/esm/src/cache/module-cache.js +214 -0
  48. package/esm/src/cache/multi-tier.d.ts +148 -0
  49. package/esm/src/cache/multi-tier.d.ts.map +1 -0
  50. package/esm/src/cache/multi-tier.js +326 -0
  51. package/esm/src/cli/app/actions.d.ts +26 -0
  52. package/esm/src/cli/app/actions.d.ts.map +1 -0
  53. package/esm/src/cli/app/actions.js +152 -0
  54. package/esm/src/cli/app/components/inline-input.d.ts +35 -0
  55. package/esm/src/cli/app/components/inline-input.d.ts.map +1 -0
  56. package/esm/src/cli/app/components/inline-input.js +220 -0
  57. package/esm/src/cli/app/components/list-select.d.ts +69 -0
  58. package/esm/src/cli/app/components/list-select.d.ts.map +1 -0
  59. package/esm/src/cli/app/components/list-select.js +137 -0
  60. package/esm/src/cli/app/index.d.ts +45 -0
  61. package/esm/src/cli/app/index.d.ts.map +1 -0
  62. package/esm/src/cli/app/index.js +1252 -0
  63. package/esm/src/cli/app/state.d.ts +122 -0
  64. package/esm/src/cli/app/state.d.ts.map +1 -0
  65. package/esm/src/cli/app/state.js +232 -0
  66. package/esm/src/cli/app/views/dashboard.d.ts +19 -0
  67. package/esm/src/cli/app/views/dashboard.d.ts.map +1 -0
  68. package/esm/src/cli/app/views/dashboard.js +178 -0
  69. package/esm/src/cli/index/command-router.d.ts.map +1 -1
  70. package/esm/src/cli/index/command-router.js +9 -39
  71. package/esm/src/cli/index/start-handler.d.ts +3 -0
  72. package/esm/src/cli/index/start-handler.d.ts.map +1 -0
  73. package/esm/src/cli/index/start-handler.js +145 -0
  74. package/esm/src/cli/mcp/index.d.ts +11 -0
  75. package/esm/src/cli/mcp/index.d.ts.map +1 -0
  76. package/esm/src/cli/mcp/index.js +10 -0
  77. package/esm/src/cli/templates/integration-loader.d.ts.map +1 -1
  78. package/esm/src/cli/templates/integration-loader.js +2 -4
  79. package/esm/src/middleware/builtin/security/redis-rate-limit.d.ts +2 -0
  80. package/esm/src/middleware/builtin/security/redis-rate-limit.d.ts.map +1 -1
  81. package/esm/src/middleware/builtin/security/redis-rate-limit.js +23 -9
  82. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.d.ts +10 -0
  83. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.d.ts.map +1 -1
  84. package/esm/src/modules/react-loader/ssr-module-loader/cache/redis.js +30 -42
  85. package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
  86. package/esm/src/modules/react-loader/ssr-module-loader/loader.js +148 -20
  87. package/esm/src/observability/tracing/span-names.d.ts +2 -0
  88. package/esm/src/observability/tracing/span-names.d.ts.map +1 -1
  89. package/esm/src/observability/tracing/span-names.js +2 -0
  90. package/esm/src/platform/adapters/fs/cache/file-cache.d.ts.map +1 -1
  91. package/esm/src/platform/adapters/fs/cache/file-cache.js +9 -3
  92. package/esm/src/rendering/orchestrator/module-loader/cache.d.ts +10 -2
  93. package/esm/src/rendering/orchestrator/module-loader/cache.d.ts.map +1 -1
  94. package/esm/src/rendering/orchestrator/module-loader/cache.js +11 -6
  95. package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
  96. package/esm/src/rendering/orchestrator/module-loader/index.js +72 -77
  97. package/esm/src/server/context/cache-invalidation.d.ts.map +1 -1
  98. package/esm/src/server/context/cache-invalidation.js +4 -0
  99. package/esm/src/server/handlers/dev/dashboard/api.js +4 -0
  100. package/esm/src/server/handlers/dev/projects/ui-handler.d.ts.map +1 -1
  101. package/esm/src/server/handlers/dev/projects/ui-handler.js +6 -0
  102. package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
  103. package/esm/src/transforms/esm/http-cache.js +145 -93
  104. package/esm/src/transforms/esm/transform-cache.d.ts +25 -0
  105. package/esm/src/transforms/esm/transform-cache.d.ts.map +1 -1
  106. package/esm/src/transforms/esm/transform-cache.js +45 -0
  107. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
  108. package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +2 -36
  109. package/esm/src/utils/constants/cache.d.ts +4 -0
  110. package/esm/src/utils/constants/cache.d.ts.map +1 -1
  111. package/esm/src/utils/constants/cache.js +14 -1
  112. package/esm/src/utils/index.d.ts +1 -1
  113. package/esm/src/utils/index.d.ts.map +1 -1
  114. package/esm/src/utils/index.js +1 -1
  115. package/package.json +2 -1
  116. package/src/deno.js +1 -1
  117. package/src/proxy/cache/index.ts +93 -0
  118. package/src/proxy/cache/memory-cache.ts +120 -0
  119. package/src/proxy/cache/redis-cache.ts +203 -0
  120. package/src/proxy/cache/resilient-cache.ts +205 -0
  121. package/src/proxy/cache/types.ts +72 -0
  122. package/src/proxy/handler.ts +593 -0
  123. package/src/proxy/logger.ts +329 -0
  124. package/src/proxy/oauth-client.ts +91 -0
  125. package/src/proxy/token-manager.ts +174 -0
  126. package/src/proxy/tracing.ts +237 -0
  127. package/src/src/cache/backend.ts +65 -0
  128. package/src/src/cache/cache-key-builder.ts +0 -9
  129. package/src/src/cache/hash.ts +205 -0
  130. package/src/src/cache/index.ts +3 -0
  131. package/src/src/cache/module-cache.ts +252 -0
  132. package/src/src/cache/multi-tier.ts +462 -0
  133. package/src/src/cli/app/actions.ts +190 -0
  134. package/src/src/cli/app/components/inline-input.ts +255 -0
  135. package/src/src/cli/app/components/list-select.ts +215 -0
  136. package/src/src/cli/app/index.ts +1471 -0
  137. package/src/src/cli/app/state.ts +385 -0
  138. package/src/src/cli/app/views/dashboard.ts +212 -0
  139. package/src/src/cli/index/command-router.ts +9 -40
  140. package/src/src/cli/index/start-handler.ts +195 -0
  141. package/src/src/cli/mcp/index.ts +11 -0
  142. package/src/src/cli/templates/integration-loader.ts +2 -8
  143. package/src/src/middleware/builtin/security/redis-rate-limit.ts +24 -11
  144. package/src/src/modules/react-loader/ssr-module-loader/cache/redis.ts +36 -50
  145. package/src/src/modules/react-loader/ssr-module-loader/loader.ts +168 -25
  146. package/src/src/observability/tracing/span-names.ts +2 -0
  147. package/src/src/platform/adapters/fs/cache/file-cache.ts +9 -3
  148. package/src/src/rendering/orchestrator/module-loader/cache.ts +14 -8
  149. package/src/src/rendering/orchestrator/module-loader/index.ts +94 -89
  150. package/src/src/server/context/cache-invalidation.ts +4 -0
  151. package/src/src/server/handlers/dev/dashboard/api.ts +2 -0
  152. package/src/src/server/handlers/dev/projects/ui-handler.ts +6 -0
  153. package/src/src/transforms/esm/http-cache.ts +160 -105
  154. package/src/src/transforms/esm/transform-cache.ts +53 -0
  155. package/src/src/transforms/mdx/esm-module-loader/module-fetcher/index.ts +2 -40
  156. package/src/src/utils/constants/cache.ts +21 -1
  157. package/src/src/utils/index.ts +0 -1
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Multi-Tier Cache Abstraction
3
+ *
4
+ * Generic implementation for L1 → L2 → L3 cache flows with automatic backfill.
5
+ * This provides consistent caching behavior across the codebase:
6
+ *
7
+ * - L1: In-memory (fastest, per-pod, lost on restart)
8
+ * - L2: Local disk (fast, per-pod, survives restart)
9
+ * - L3: Distributed (Redis/API, cross-pod, shared state)
10
+ *
11
+ * When a cache hit occurs at a lower tier (e.g., L3), the value is automatically
12
+ * backfilled to higher tiers (L1, L2) for faster subsequent access.
13
+ *
14
+ * @module cache/multi-tier
15
+ */
16
+ import { rendererLogger as logger } from "../utils/index.js";
17
+ import { withSpan } from "../observability/tracing/otlp-setup.js";
18
+ import { SpanNames } from "../observability/tracing/span-names.js";
19
+ /**
20
+ * Multi-tier cache implementation.
21
+ *
22
+ * Provides automatic fallthrough from L1 → L2 → L3 with backfill on hits.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const cache = new MultiTierCache({
27
+ * name: "http-module",
28
+ * l1: new MemoryTier(),
29
+ * l3: await CacheBackends.httpModule(),
30
+ * defaultTtlSeconds: 86400,
31
+ * });
32
+ *
33
+ * const value = await cache.get("my-key");
34
+ * // If found in L3, automatically backfills L1
35
+ * ```
36
+ */
37
+ export class MultiTierCache {
38
+ config;
39
+ stats = {
40
+ gets: 0,
41
+ l1Hits: 0,
42
+ l2Hits: 0,
43
+ l3Hits: 0,
44
+ misses: 0,
45
+ sets: 0,
46
+ backfills: 0,
47
+ };
48
+ constructor(config) {
49
+ this.config = {
50
+ defaultTtlSeconds: 300,
51
+ backfillOnHit: true,
52
+ asyncBackfill: true,
53
+ ...config,
54
+ };
55
+ }
56
+ /**
57
+ * Get a value from the cache.
58
+ *
59
+ * Checks tiers in order: L1 → L2 → L3.
60
+ * On hit at a lower tier, backfills higher tiers.
61
+ */
62
+ get(key) {
63
+ return withSpan(SpanNames.CACHE_MULTI_TIER_GET, async (span) => {
64
+ this.stats.gets++;
65
+ span?.setAttribute("cache.name", this.config.name);
66
+ span?.setAttribute("cache.key", key);
67
+ // L1: Memory
68
+ if (this.config.l1) {
69
+ try {
70
+ const value = await this.config.l1.get(key);
71
+ if (value !== null) {
72
+ this.stats.l1Hits++;
73
+ span?.setAttribute("cache.hit_tier", "l1");
74
+ logger.debug(`[${this.config.name}] L1 hit`, { key });
75
+ return value;
76
+ }
77
+ }
78
+ catch (error) {
79
+ logger.debug(`[${this.config.name}] L1 get error`, { key, error });
80
+ }
81
+ }
82
+ // L2: Disk
83
+ if (this.config.l2) {
84
+ try {
85
+ const value = await this.config.l2.get(key);
86
+ if (value !== null) {
87
+ this.stats.l2Hits++;
88
+ span?.setAttribute("cache.hit_tier", "l2");
89
+ logger.debug(`[${this.config.name}] L2 hit`, { key });
90
+ const backfillPromise = this.backfill(key, value, ["l1"]);
91
+ if (this.config.asyncBackfill) {
92
+ void backfillPromise;
93
+ }
94
+ else {
95
+ await backfillPromise;
96
+ }
97
+ return value;
98
+ }
99
+ }
100
+ catch (error) {
101
+ logger.debug(`[${this.config.name}] L2 get error`, { key, error });
102
+ }
103
+ }
104
+ // L3: Distributed
105
+ if (this.config.l3) {
106
+ try {
107
+ const value = await this.config.l3.get(key);
108
+ if (value !== null) {
109
+ this.stats.l3Hits++;
110
+ span?.setAttribute("cache.hit_tier", "l3");
111
+ logger.debug(`[${this.config.name}] L3 hit`, { key });
112
+ const backfillPromise = this.backfill(key, value, ["l1", "l2"]);
113
+ if (this.config.asyncBackfill) {
114
+ void backfillPromise;
115
+ }
116
+ else {
117
+ await backfillPromise;
118
+ }
119
+ return value;
120
+ }
121
+ }
122
+ catch (error) {
123
+ logger.debug(`[${this.config.name}] L3 get error`, { key, error });
124
+ }
125
+ }
126
+ this.stats.misses++;
127
+ span?.setAttribute("cache.hit_tier", "miss");
128
+ return null;
129
+ }, { "cache.operation": "get" });
130
+ }
131
+ /**
132
+ * Set a value in all tiers.
133
+ *
134
+ * Writes to all configured tiers in parallel (or sequentially if asyncBackfill=false).
135
+ */
136
+ set(key, value, ttlSeconds) {
137
+ return withSpan(SpanNames.CACHE_MULTI_TIER_SET, (span) => {
138
+ this.stats.sets++;
139
+ const ttl = ttlSeconds ?? this.config.defaultTtlSeconds;
140
+ span?.setAttribute("cache.name", this.config.name);
141
+ span?.setAttribute("cache.key", key);
142
+ span?.setAttribute("cache.ttl_seconds", ttl);
143
+ const tiers = [this.config.l1, this.config.l2, this.config.l3].filter((t) => t !== undefined);
144
+ const setOps = tiers.map((tier) => tier.set(key, value, ttl).catch((error) => {
145
+ logger.debug(`[${this.config.name}] Set error in ${tier.name}`, { key, error });
146
+ }));
147
+ if (this.config.asyncBackfill) {
148
+ // Fire-and-forget for performance (don't await)
149
+ void Promise.all(setOps);
150
+ return Promise.resolve();
151
+ }
152
+ // Wait for all tiers
153
+ return Promise.all(setOps).then(() => { });
154
+ }, { "cache.operation": "set" });
155
+ }
156
+ /**
157
+ * Delete a value from all tiers.
158
+ */
159
+ async delete(key) {
160
+ const tiers = [this.config.l1, this.config.l2, this.config.l3].filter((t) => t !== undefined && t.delete !== undefined);
161
+ await Promise.all(tiers.map((tier) => tier.delete?.(key).catch((error) => {
162
+ logger.debug(`[${this.config.name}] Delete error in ${tier.name}`, { key, error });
163
+ })));
164
+ }
165
+ /**
166
+ * Get or compute a value.
167
+ *
168
+ * If the key exists in any tier, returns it.
169
+ * Otherwise, calls the compute function and stores the result in all tiers.
170
+ */
171
+ async getOrCompute(key, computeFn, ttlSeconds) {
172
+ const cached = await this.get(key);
173
+ if (cached !== null)
174
+ return cached;
175
+ const value = await computeFn();
176
+ await this.set(key, value, ttlSeconds);
177
+ return value;
178
+ }
179
+ /**
180
+ * Batch get multiple values.
181
+ *
182
+ * Uses batch operations where available for efficiency.
183
+ * Returns a map of key → value (null if not found).
184
+ */
185
+ async getBatch(keys) {
186
+ if (keys.length === 0)
187
+ return new Map();
188
+ const results = new Map();
189
+ let remainingKeys = [...keys];
190
+ const backfillPromises = [];
191
+ // Check L1
192
+ if (this.config.l1 && remainingKeys.length > 0) {
193
+ try {
194
+ const l1Results = this.config.l1.getBatch
195
+ ? await this.config.l1.getBatch(remainingKeys)
196
+ : await this.individualGets(this.config.l1, remainingKeys);
197
+ for (const [key, value] of l1Results) {
198
+ if (value !== null) {
199
+ results.set(key, value);
200
+ this.stats.l1Hits++;
201
+ }
202
+ }
203
+ remainingKeys = remainingKeys.filter((k) => !results.has(k) || results.get(k) === null);
204
+ }
205
+ catch (error) {
206
+ logger.debug(`[${this.config.name}] L1 getBatch error`, {
207
+ keyCount: remainingKeys.length,
208
+ error,
209
+ });
210
+ }
211
+ }
212
+ // Check L2
213
+ if (this.config.l2 && remainingKeys.length > 0) {
214
+ try {
215
+ const l2Results = this.config.l2.getBatch
216
+ ? await this.config.l2.getBatch(remainingKeys)
217
+ : await this.individualGets(this.config.l2, remainingKeys);
218
+ for (const [key, value] of l2Results) {
219
+ if (value !== null) {
220
+ results.set(key, value);
221
+ this.stats.l2Hits++;
222
+ backfillPromises.push(this.backfill(key, value, ["l1"]));
223
+ }
224
+ }
225
+ remainingKeys = remainingKeys.filter((k) => !results.has(k) || results.get(k) === null);
226
+ }
227
+ catch (error) {
228
+ logger.debug(`[${this.config.name}] L2 getBatch error`, {
229
+ keyCount: remainingKeys.length,
230
+ error,
231
+ });
232
+ }
233
+ }
234
+ // Check L3
235
+ if (this.config.l3 && remainingKeys.length > 0) {
236
+ try {
237
+ const l3Results = this.config.l3.getBatch
238
+ ? await this.config.l3.getBatch(remainingKeys)
239
+ : await this.individualGets(this.config.l3, remainingKeys);
240
+ for (const [key, value] of l3Results) {
241
+ if (value !== null) {
242
+ results.set(key, value);
243
+ this.stats.l3Hits++;
244
+ backfillPromises.push(this.backfill(key, value, ["l1", "l2"]));
245
+ }
246
+ else {
247
+ results.set(key, null);
248
+ this.stats.misses++;
249
+ }
250
+ }
251
+ }
252
+ catch (error) {
253
+ logger.debug(`[${this.config.name}] L3 getBatch error`, {
254
+ keyCount: remainingKeys.length,
255
+ error,
256
+ });
257
+ }
258
+ }
259
+ // Mark remaining as misses
260
+ for (const key of remainingKeys) {
261
+ if (!results.has(key)) {
262
+ results.set(key, null);
263
+ this.stats.misses++;
264
+ }
265
+ }
266
+ if (backfillPromises.length > 0) {
267
+ if (this.config.asyncBackfill) {
268
+ void Promise.all(backfillPromises);
269
+ }
270
+ else {
271
+ await Promise.all(backfillPromises);
272
+ }
273
+ }
274
+ return results;
275
+ }
276
+ /**
277
+ * Get cache statistics.
278
+ */
279
+ getStats() {
280
+ const totalHits = this.stats.l1Hits + this.stats.l2Hits + this.stats.l3Hits;
281
+ const hitRate = this.stats.gets > 0 ? totalHits / this.stats.gets : 0;
282
+ return { ...this.stats, hitRate };
283
+ }
284
+ /**
285
+ * Reset statistics.
286
+ */
287
+ resetStats() {
288
+ this.stats = {
289
+ gets: 0,
290
+ l1Hits: 0,
291
+ l2Hits: 0,
292
+ l3Hits: 0,
293
+ misses: 0,
294
+ sets: 0,
295
+ backfills: 0,
296
+ };
297
+ }
298
+ /**
299
+ * Backfill higher tiers with a value found at a lower tier.
300
+ */
301
+ backfill(key, value, tiers) {
302
+ if (!this.config.backfillOnHit)
303
+ return Promise.resolve();
304
+ this.stats.backfills++;
305
+ const ttl = this.config.defaultTtlSeconds;
306
+ const backfillOps = [];
307
+ if (tiers.includes("l1") && this.config.l1) {
308
+ backfillOps.push(this.config.l1.set(key, value, ttl).catch((error) => {
309
+ logger.debug(`[${this.config.name}] L1 backfill error`, { key, error });
310
+ }));
311
+ }
312
+ if (tiers.includes("l2") && this.config.l2) {
313
+ backfillOps.push(this.config.l2.set(key, value, ttl).catch((error) => {
314
+ logger.debug(`[${this.config.name}] L2 backfill error`, { key, error });
315
+ }));
316
+ }
317
+ return Promise.all(backfillOps).then(() => { });
318
+ }
319
+ /**
320
+ * Helper for individual gets when batch operation is not available.
321
+ */
322
+ async individualGets(tier, keys) {
323
+ const results = await Promise.all(keys.map(async (key) => [key, await tier.get(key)]));
324
+ return new Map(results);
325
+ }
326
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * CLI App Actions
3
+ *
4
+ * Handlers for opening projects in browser, Studio, and IDE.
5
+ * Uses cross-runtime platform abstractions for filesystem and command execution.
6
+ */
7
+ import type { ProjectInfo } from "./state.js";
8
+ import { type RuntimeEnv } from "../../config/runtime-env.js";
9
+ export type IDE = "cursor" | "code" | "zed" | "idea" | "webstorm";
10
+ export interface ActionResult {
11
+ success: boolean;
12
+ message?: string;
13
+ }
14
+ export declare function openInBrowser(project: ProjectInfo, port: number): Promise<ActionResult>;
15
+ export declare function openInStudio(project: ProjectInfo): Promise<ActionResult>;
16
+ export declare function detectIDEs(): Promise<IDE[]>;
17
+ export declare function getPreferredIDE(): Promise<IDE | null>;
18
+ export declare function openInIDE(project: ProjectInfo, ide?: IDE): Promise<ActionResult>;
19
+ export declare function openFileInIDE(filePath: string, ide?: IDE): Promise<ActionResult>;
20
+ export declare function clearProjectCache(project: ProjectInfo): Promise<ActionResult>;
21
+ export declare function openMCPSettings(env?: RuntimeEnv): Promise<ActionResult>;
22
+ export declare function quickOpen(projects: Array<{
23
+ slug: string;
24
+ path: string;
25
+ }>, num: number, port: number): Promise<ActionResult>;
26
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/app/actions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE7E,MAAM,MAAM,GAAG,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiDD,wBAAsB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAS7F;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAS9E;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAUjD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAG3D;AAsBD,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAMtF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAEhF;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAgBnF;AAED,wBAAsB,eAAe,CAAC,GAAG,GAAE,UAA4B,GAAG,OAAO,CAAC,YAAY,CAAC,CAkB9F;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAQvB"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * CLI App Actions
3
+ *
4
+ * Handlers for opening projects in browser, Studio, and IDE.
5
+ * Uses cross-runtime platform abstractions for filesystem and command execution.
6
+ */
7
+ import { openBrowser } from "../auth/browser.js";
8
+ import { createFileSystem } from "../../platform/compat/fs.js";
9
+ import { getOsType, runCommand } from "../../platform/compat/process.js";
10
+ import { join } from "../../platform/compat/path/index.js";
11
+ import { getRuntimeEnv } from "../../config/runtime-env.js";
12
+ /** IDE command-line executables */
13
+ const IDE_COMMANDS = {
14
+ cursor: "cursor",
15
+ code: "code",
16
+ zed: "zed",
17
+ idea: "idea",
18
+ webstorm: "webstorm",
19
+ };
20
+ /** IDE display names */
21
+ const IDE_NAMES = {
22
+ cursor: "Cursor",
23
+ code: "VS Code",
24
+ zed: "Zed",
25
+ idea: "IntelliJ IDEA",
26
+ webstorm: "WebStorm",
27
+ };
28
+ /** IDE detection order (preferred first) */
29
+ const IDE_DETECTION_ORDER = ["cursor", "code", "zed", "idea", "webstorm"];
30
+ /** Cache directories to clear relative to project path */
31
+ const PROJECT_CACHE_DIRS = [".cache", "node_modules/.cache"];
32
+ function formatError(error) {
33
+ return error instanceof Error ? error.message : String(error);
34
+ }
35
+ async function commandExists(cmd) {
36
+ try {
37
+ const whichCmd = getOsType() === "windows" ? "where" : "which";
38
+ const result = await runCommand(whichCmd, { args: [cmd] });
39
+ return result.success;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ async function runCommandLocal(cmd, args) {
46
+ try {
47
+ const result = await runCommand(cmd, { args });
48
+ return result.success;
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ export async function openInBrowser(project, port) {
55
+ const url = `http://${project.slug}.veryfront.me:${port}`;
56
+ try {
57
+ await openBrowser(url);
58
+ return { success: true, message: `Opened ${url}` };
59
+ }
60
+ catch (error) {
61
+ return { success: false, message: `Failed to open browser: ${formatError(error)}` };
62
+ }
63
+ }
64
+ export async function openInStudio(project) {
65
+ const url = `https://veryfront.com/projects/${project.slug}`;
66
+ try {
67
+ await openBrowser(url);
68
+ return { success: true, message: `Opened Studio for ${project.slug}` };
69
+ }
70
+ catch (error) {
71
+ return { success: false, message: `Failed to open Studio: ${formatError(error)}` };
72
+ }
73
+ }
74
+ export async function detectIDEs() {
75
+ const available = [];
76
+ for (const ide of IDE_DETECTION_ORDER) {
77
+ if (await commandExists(IDE_COMMANDS[ide])) {
78
+ available.push(ide);
79
+ }
80
+ }
81
+ return available;
82
+ }
83
+ export async function getPreferredIDE() {
84
+ const ides = await detectIDEs();
85
+ return ides[0] ?? null;
86
+ }
87
+ async function openPathInIDE(path, ide) {
88
+ const targetIDE = ide ?? (await getPreferredIDE());
89
+ if (!targetIDE) {
90
+ return {
91
+ success: false,
92
+ message: "No supported IDE found. Install VS Code, Cursor, or Zed.",
93
+ };
94
+ }
95
+ const cmd = IDE_COMMANDS[targetIDE];
96
+ const name = IDE_NAMES[targetIDE];
97
+ if (await runCommandLocal(cmd, [path])) {
98
+ return { success: true, message: `Opened in ${name}` };
99
+ }
100
+ return { success: false, message: `Failed to open ${name}` };
101
+ }
102
+ export async function openInIDE(project, ide) {
103
+ const result = await openPathInIDE(project.path, ide);
104
+ if (!result.success)
105
+ return result;
106
+ const ideName = result.message?.split(" in ")[1];
107
+ return { success: true, message: `Opened ${project.slug} in ${ideName}` };
108
+ }
109
+ export function openFileInIDE(filePath, ide) {
110
+ return openPathInIDE(filePath, ide);
111
+ }
112
+ export async function clearProjectCache(project) {
113
+ const fs = createFileSystem();
114
+ let cleared = 0;
115
+ for (const relativeDir of PROJECT_CACHE_DIRS) {
116
+ const dir = join(project.path, relativeDir);
117
+ try {
118
+ await fs.remove(dir, { recursive: true });
119
+ cleared++;
120
+ }
121
+ catch {
122
+ // Directory doesn't exist
123
+ }
124
+ }
125
+ const message = cleared > 0 ? `Cleared ${cleared} cache directories` : "No caches to clear";
126
+ return { success: true, message };
127
+ }
128
+ export async function openMCPSettings(env = getRuntimeEnv()) {
129
+ const home = env.homeDir || "";
130
+ const claudeDir = join(home, ".claude");
131
+ const settingsPath = join(claudeDir, "settings.json");
132
+ const fs = createFileSystem();
133
+ try {
134
+ await fs.mkdir(claudeDir, { recursive: true });
135
+ }
136
+ catch {
137
+ // Already exists
138
+ }
139
+ if (!(await fs.exists(settingsPath))) {
140
+ const defaultSettings = { mcpServers: {} };
141
+ await fs.writeTextFile(settingsPath, JSON.stringify(defaultSettings, null, 2));
142
+ }
143
+ return openFileInIDE(settingsPath);
144
+ }
145
+ export function quickOpen(projects, num, port) {
146
+ const index = num - 1;
147
+ if (index < 0 || index >= projects.length) {
148
+ return Promise.resolve({ success: false, message: `No project at position ${num}` });
149
+ }
150
+ const project = projects[index];
151
+ return openInBrowser({ slug: project.slug, path: project.path, type: "local" }, port);
152
+ }
@@ -0,0 +1,35 @@
1
+ /****
2
+ * Inline Text Input Component
3
+ *
4
+ * Renders an input prompt at the bottom of the TUI that stays inline
5
+ * without exiting alternate screen mode.
6
+ */
7
+ import type { InputState, LogEntry } from "../state.js";
8
+ export interface InlineInputOptions {
9
+ maxWidth?: number;
10
+ }
11
+ /**
12
+ * Render the inline input prompt
13
+ */
14
+ export declare function renderInput(input: InputState, _options?: InlineInputOptions): string;
15
+ export interface RenderLogsOptions {
16
+ maxLines?: number;
17
+ maxWidth?: number;
18
+ scroll?: number;
19
+ expanded?: boolean;
20
+ }
21
+ /**
22
+ * Render the logs area with optional scrolling
23
+ */
24
+ export declare function renderLogs(logs: LogEntry[], options?: RenderLogsOptions): string;
25
+ /**
26
+ * Handle input key press
27
+ * Returns the new value and cursor position, or null if the key should end input
28
+ */
29
+ export declare function handleInputKey(key: string, value: string, cursorPos: number): {
30
+ value: string;
31
+ cursorPos: number;
32
+ } | {
33
+ action: "submit" | "cancel";
34
+ };
35
+ //# sourceMappingURL=inline-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-input.d.ts","sourceRoot":"","sources":["../../../../../src/src/cli/app/components/inline-input.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,GAAE,kBAAuB,GAAG,MAAM,CAkBxF;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,QAAQ,EAAE,EAChB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CA4ER;AAuED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAiDxE"}