@ottocode/server 0.1.175 → 0.1.177
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.
- package/package.json +3 -3
- package/src/routes/files.ts +104 -41
- package/src/routes/setu.ts +1 -1
- package/sst-env.d.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottocode/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.177",
|
|
4
4
|
"description": "HTTP API server for ottocode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"typecheck": "tsc --noEmit"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ottocode/sdk": "0.1.
|
|
33
|
-
"@ottocode/database": "0.1.
|
|
32
|
+
"@ottocode/sdk": "0.1.177",
|
|
33
|
+
"@ottocode/database": "0.1.177",
|
|
34
34
|
"drizzle-orm": "^0.44.5",
|
|
35
35
|
"hono": "^4.9.9",
|
|
36
36
|
"zod": "^4.1.8"
|
package/src/routes/files.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import { readdir, readFile } from 'node:fs/promises';
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
4
5
|
import { exec } from 'node:child_process';
|
|
5
6
|
import { promisify } from 'node:util';
|
|
6
7
|
import { serializeError } from '../runtime/errors/api-error.ts';
|
|
7
8
|
import { logger } from '@ottocode/sdk';
|
|
9
|
+
import { resolveBinary } from '@ottocode/sdk/tools/bin-manager';
|
|
8
10
|
|
|
9
11
|
const execAsync = promisify(exec);
|
|
10
12
|
|
|
11
|
-
const
|
|
13
|
+
const EXCLUDED_FILES = new Set([
|
|
14
|
+
'.DS_Store',
|
|
15
|
+
'bun.lockb',
|
|
16
|
+
'.env',
|
|
17
|
+
'.env.local',
|
|
18
|
+
'.env.production',
|
|
19
|
+
'.env.development',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const EXCLUDED_DIRS = new Set([
|
|
12
23
|
'node_modules',
|
|
13
24
|
'.git',
|
|
14
25
|
'dist',
|
|
@@ -16,26 +27,72 @@ const EXCLUDED_PATTERNS = [
|
|
|
16
27
|
'.next',
|
|
17
28
|
'.nuxt',
|
|
18
29
|
'.turbo',
|
|
30
|
+
'.astro',
|
|
31
|
+
'.svelte-kit',
|
|
32
|
+
'.vercel',
|
|
33
|
+
'.output',
|
|
19
34
|
'coverage',
|
|
20
35
|
'.cache',
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
'.env.local',
|
|
25
|
-
'.env.production',
|
|
26
|
-
'.env.development',
|
|
27
|
-
];
|
|
36
|
+
'__pycache__',
|
|
37
|
+
'.tsbuildinfo',
|
|
38
|
+
]);
|
|
28
39
|
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
function shouldExcludeFile(name: string): boolean {
|
|
41
|
+
return EXCLUDED_FILES.has(name);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function shouldExcludeDir(name: string): boolean {
|
|
45
|
+
return EXCLUDED_DIRS.has(name);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function listFilesWithRg(
|
|
49
|
+
projectRoot: string,
|
|
50
|
+
limit: number,
|
|
51
|
+
): Promise<{ files: string[]; truncated: boolean }> {
|
|
52
|
+
const rgBin = await resolveBinary('rg');
|
|
53
|
+
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const args = [
|
|
56
|
+
'--files',
|
|
57
|
+
'--hidden',
|
|
58
|
+
'--glob', '!.git/',
|
|
59
|
+
'--sort', 'path',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const proc = spawn(rgBin, args, { cwd: projectRoot });
|
|
63
|
+
let stdout = '';
|
|
64
|
+
let stderr = '';
|
|
65
|
+
|
|
66
|
+
proc.stdout.on('data', (data) => {
|
|
67
|
+
stdout += data.toString();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
proc.stderr.on('data', (data) => {
|
|
71
|
+
stderr += data.toString();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
proc.on('close', (code) => {
|
|
75
|
+
if (code !== 0 && code !== 1) {
|
|
76
|
+
logger.warn('rg --files failed, falling back', { stderr } as Record<string, unknown>);
|
|
77
|
+
resolve({ files: [], truncated: false });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const allFiles = stdout.split('\n').filter(Boolean);
|
|
82
|
+
|
|
83
|
+
const filtered = allFiles.filter((f) => {
|
|
84
|
+
const filename = f.split('/').pop() || f;
|
|
85
|
+
return !shouldExcludeFile(filename);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const truncated = filtered.length > limit;
|
|
89
|
+
resolve({ files: filtered.slice(0, limit), truncated });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
proc.on('error', () => {
|
|
93
|
+
resolve({ files: [], truncated: false });
|
|
94
|
+
});
|
|
95
|
+
});
|
|
39
96
|
}
|
|
40
97
|
|
|
41
98
|
async function parseGitignore(projectRoot: string): Promise<Set<string>> {
|
|
@@ -104,21 +161,17 @@ async function traverseDirectory(
|
|
|
104
161
|
return { files: collected, truncated: true };
|
|
105
162
|
}
|
|
106
163
|
|
|
107
|
-
if (shouldExclude(entry.name)) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
164
|
const fullPath = join(dir, entry.name);
|
|
112
165
|
const relativePath = relative(projectRoot, fullPath);
|
|
113
166
|
|
|
114
|
-
if (
|
|
115
|
-
gitignorePatterns &&
|
|
116
|
-
matchesGitignorePattern(relativePath, gitignorePatterns)
|
|
117
|
-
) {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
167
|
if (entry.isDirectory()) {
|
|
168
|
+
if (shouldExcludeDir(entry.name)) continue;
|
|
169
|
+
if (
|
|
170
|
+
gitignorePatterns &&
|
|
171
|
+
matchesGitignorePattern(relativePath, gitignorePatterns)
|
|
172
|
+
) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
122
175
|
const result = await traverseDirectory(
|
|
123
176
|
fullPath,
|
|
124
177
|
projectRoot,
|
|
@@ -132,11 +185,18 @@ async function traverseDirectory(
|
|
|
132
185
|
return result;
|
|
133
186
|
}
|
|
134
187
|
} else if (entry.isFile()) {
|
|
188
|
+
if (shouldExcludeFile(entry.name)) continue;
|
|
189
|
+
if (
|
|
190
|
+
gitignorePatterns &&
|
|
191
|
+
matchesGitignorePattern(relativePath, gitignorePatterns)
|
|
192
|
+
) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
135
195
|
collected.push(relativePath);
|
|
136
196
|
}
|
|
137
197
|
}
|
|
138
198
|
} catch (err) {
|
|
139
|
-
logger.warn(`Failed to read directory ${dir}:`, err);
|
|
199
|
+
logger.warn(`Failed to read directory ${dir}:`, err as Record<string, unknown>);
|
|
140
200
|
}
|
|
141
201
|
|
|
142
202
|
return { files: collected, truncated: false };
|
|
@@ -167,7 +227,7 @@ async function getChangedFiles(
|
|
|
167
227
|
}
|
|
168
228
|
return changedFiles;
|
|
169
229
|
} catch (_err) {
|
|
170
|
-
return new
|
|
230
|
+
return new Map();
|
|
171
231
|
}
|
|
172
232
|
}
|
|
173
233
|
|
|
@@ -178,17 +238,20 @@ export function registerFilesRoutes(app: Hono) {
|
|
|
178
238
|
const maxDepth = Number.parseInt(c.req.query('maxDepth') || '10', 10);
|
|
179
239
|
const limit = Number.parseInt(c.req.query('limit') || '1000', 10);
|
|
180
240
|
|
|
181
|
-
|
|
241
|
+
let result = await listFilesWithRg(projectRoot, limit);
|
|
182
242
|
|
|
183
|
-
|
|
184
|
-
projectRoot
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
243
|
+
if (result.files.length === 0) {
|
|
244
|
+
const gitignorePatterns = await parseGitignore(projectRoot);
|
|
245
|
+
result = await traverseDirectory(
|
|
246
|
+
projectRoot,
|
|
247
|
+
projectRoot,
|
|
248
|
+
maxDepth,
|
|
249
|
+
0,
|
|
250
|
+
limit,
|
|
251
|
+
[],
|
|
252
|
+
gitignorePatterns,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
192
255
|
|
|
193
256
|
const changedFiles = await getChangedFiles(projectRoot);
|
|
194
257
|
|
package/src/routes/setu.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
type TopupMethod,
|
|
20
20
|
} from '../runtime/topup/manager.ts';
|
|
21
21
|
|
|
22
|
-
const SETU_BASE_URL = process.env.SETU_BASE_URL || 'https://api.setu.
|
|
22
|
+
const SETU_BASE_URL = process.env.SETU_BASE_URL || 'https://api.setu.ottocode.io';
|
|
23
23
|
|
|
24
24
|
function getSetuBaseUrl(): string {
|
|
25
25
|
return SETU_BASE_URL.endsWith('/')
|
package/sst-env.d.ts
CHANGED