@sentry/junior 0.1.1 → 0.3.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.
- package/README.md +10 -165
- package/bin/junior.mjs +38 -128
- package/dist/app/layout.d.ts +3 -0
- package/dist/{bot-6KXJ366H.js → bot-JSIREVQD.js} +4 -3
- package/dist/chunk-4RFOJSJL.js +272 -0
- package/dist/chunk-DPTR2FNH.js +1866 -0
- package/dist/{chunk-5LLCJPTH.js → chunk-L745IWNK.js} +7132 -5459
- package/dist/{chunk-BBOVH5RF.js → chunk-PY4AI2GZ.js} +62 -15
- package/dist/{chunk-OVG2HBNM.js → chunk-RTQMRGZD.js} +2 -2
- package/dist/chunk-SP6LV35L.js +328 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +105 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.js +30 -0
- package/dist/cli/snapshot-warmup.d.ts +3 -0
- package/dist/cli/snapshot-warmup.js +58 -0
- package/dist/handlers/health.d.ts +3 -0
- package/dist/handlers/queue-callback.d.ts +7 -0
- package/dist/handlers/queue-callback.js +6 -266
- package/dist/handlers/router.d.ts +18 -3
- package/dist/handlers/router.js +321 -13
- package/dist/handlers/webhooks.d.ts +13 -0
- package/dist/handlers/webhooks.js +2 -2
- package/dist/instrumentation.d.ts +6 -0
- package/dist/next-config.d.ts +10 -2
- package/dist/next-config.js +58 -57
- package/package.json +3 -8
- package/dist/chunk-CJFEZLEN.js +0 -3136
- package/dist/route-DMVINKJW.js +0 -304
|
@@ -225,13 +225,21 @@ function emitSentry(level, body, attributes) {
|
|
|
225
225
|
loggerFn(body, attributes);
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
228
|
+
const sentryWithScope = sentry.withScope;
|
|
229
|
+
const sentryCaptureMessage = sentry.captureMessage;
|
|
230
|
+
const sentryLevel = level === "warn" ? "warning" : level;
|
|
231
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureMessage === "function") {
|
|
232
|
+
sentryWithScope((scope) => {
|
|
233
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
234
|
+
scope.setExtra(key, value);
|
|
235
|
+
}
|
|
236
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
237
|
+
});
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (typeof sentryCaptureMessage === "function") {
|
|
241
|
+
sentryCaptureMessage(body, sentryLevel);
|
|
242
|
+
}
|
|
235
243
|
}
|
|
236
244
|
function formatConsoleLevel(level) {
|
|
237
245
|
if (level === "debug") return "DBG";
|
|
@@ -353,12 +361,22 @@ var log = {
|
|
|
353
361
|
"exception.message": normalizedError.message,
|
|
354
362
|
"exception.stacktrace": normalizedError.stack
|
|
355
363
|
}, body ?? normalizedError.message);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
364
|
+
let eventId;
|
|
365
|
+
const sentryWithScope = Sentry.withScope;
|
|
366
|
+
const sentryCaptureException = Sentry.captureException;
|
|
367
|
+
if (typeof sentryWithScope === "function" && typeof sentryCaptureException === "function") {
|
|
368
|
+
sentryWithScope((scope) => {
|
|
369
|
+
for (const [key, value] of Object.entries(mergeAttributes(contextStorage.getStore(), attrs))) {
|
|
370
|
+
scope.setExtra(key, value);
|
|
371
|
+
}
|
|
372
|
+
eventId = sentryCaptureException(normalizedError);
|
|
373
|
+
});
|
|
374
|
+
return eventId;
|
|
375
|
+
}
|
|
376
|
+
if (typeof sentryCaptureException === "function") {
|
|
377
|
+
eventId = sentryCaptureException(normalizedError);
|
|
378
|
+
}
|
|
379
|
+
return eventId;
|
|
362
380
|
}
|
|
363
381
|
};
|
|
364
382
|
function withLogContext(context, callback) {
|
|
@@ -437,7 +455,7 @@ function logError(eventName, context = {}, attributes = {}, body) {
|
|
|
437
455
|
}
|
|
438
456
|
function logException(error, eventName, context = {}, attributes = {}, body) {
|
|
439
457
|
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
440
|
-
log.exception(eventName, normalizedError, toContextAndAttributes(context, attributes), body);
|
|
458
|
+
return log.exception(eventName, normalizedError, toContextAndAttributes(context, attributes), body);
|
|
441
459
|
}
|
|
442
460
|
function setTags(context = {}) {
|
|
443
461
|
setLogContext(context);
|
|
@@ -504,6 +522,34 @@ function setSpanStatus(status) {
|
|
|
504
522
|
function toOptionalString(value) {
|
|
505
523
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
506
524
|
}
|
|
525
|
+
function getActiveTraceId() {
|
|
526
|
+
const sentry = Sentry2;
|
|
527
|
+
if (typeof sentry.getActiveSpan !== "function" || typeof sentry.spanToJSON !== "function") {
|
|
528
|
+
return void 0;
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
const span = sentry.getActiveSpan();
|
|
532
|
+
if (!span) {
|
|
533
|
+
return void 0;
|
|
534
|
+
}
|
|
535
|
+
return toOptionalString(sentry.spanToJSON(span).trace_id);
|
|
536
|
+
} catch {
|
|
537
|
+
return void 0;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function resolveErrorReference(eventId) {
|
|
541
|
+
const traceId = getActiveTraceId();
|
|
542
|
+
if (!eventId && !traceId) {
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
if (!traceId) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
return {
|
|
549
|
+
traceId,
|
|
550
|
+
...eventId ? { eventId } : {}
|
|
551
|
+
};
|
|
552
|
+
}
|
|
507
553
|
|
|
508
554
|
export {
|
|
509
555
|
logInfo,
|
|
@@ -516,5 +562,6 @@ export {
|
|
|
516
562
|
withSpan,
|
|
517
563
|
setSpanAttributes,
|
|
518
564
|
setSpanStatus,
|
|
519
|
-
toOptionalString
|
|
565
|
+
toOptionalString,
|
|
566
|
+
resolveErrorReference
|
|
520
567
|
};
|
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
setSpanStatus,
|
|
7
7
|
withContext,
|
|
8
8
|
withSpan
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PY4AI2GZ.js";
|
|
10
10
|
|
|
11
11
|
// src/handlers/webhooks.ts
|
|
12
12
|
import { after } from "next/server";
|
|
13
13
|
import * as Sentry from "@sentry/nextjs";
|
|
14
14
|
async function loadBot() {
|
|
15
|
-
const { bot } = await import("./bot-
|
|
15
|
+
const { bot } = await import("./bot-JSIREVQD.js");
|
|
16
16
|
return bot;
|
|
17
17
|
}
|
|
18
18
|
async function POST(request, context) {
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// src/chat/fs-utils.ts
|
|
2
|
+
import { statSync } from "fs";
|
|
3
|
+
function isDirectory(targetPath) {
|
|
4
|
+
try {
|
|
5
|
+
return statSync(targetPath).isDirectory();
|
|
6
|
+
} catch {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function isFile(targetPath) {
|
|
11
|
+
try {
|
|
12
|
+
return statSync(targetPath).isFile();
|
|
13
|
+
} catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/chat/discovery-roots.ts
|
|
19
|
+
import { readdirSync } from "fs";
|
|
20
|
+
import path from "path";
|
|
21
|
+
import { fileURLToPath } from "url";
|
|
22
|
+
function normalizePath(targetPath) {
|
|
23
|
+
return path.resolve(targetPath);
|
|
24
|
+
}
|
|
25
|
+
function uniqueResolvedPathsInOrder(values) {
|
|
26
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27
|
+
const resolved = [];
|
|
28
|
+
for (const value of values) {
|
|
29
|
+
const normalized = normalizePath(value);
|
|
30
|
+
if (seen.has(normalized)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
seen.add(normalized);
|
|
34
|
+
resolved.push(normalized);
|
|
35
|
+
}
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
38
|
+
function isNodeModulesPath(candidatePath) {
|
|
39
|
+
return path.basename(candidatePath) === "node_modules";
|
|
40
|
+
}
|
|
41
|
+
function isInsidePnpmStore(candidatePath) {
|
|
42
|
+
return candidatePath.split(path.sep).includes(".pnpm");
|
|
43
|
+
}
|
|
44
|
+
function runningFromInstalledPackage() {
|
|
45
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
46
|
+
const marker = `${path.sep}node_modules${path.sep}@sentry${path.sep}junior${path.sep}`;
|
|
47
|
+
return currentFile.includes(marker);
|
|
48
|
+
}
|
|
49
|
+
function listInstalledPackageNodeModulesDirs() {
|
|
50
|
+
if (!runningFromInstalledPackage()) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const dirs = [];
|
|
54
|
+
let current = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
|
|
55
|
+
while (true) {
|
|
56
|
+
if (isNodeModulesPath(current) && !isInsidePnpmStore(current) && isDirectory(current)) {
|
|
57
|
+
dirs.push(current);
|
|
58
|
+
}
|
|
59
|
+
const parent = path.dirname(current);
|
|
60
|
+
if (parent === current) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
current = parent;
|
|
64
|
+
}
|
|
65
|
+
return dirs;
|
|
66
|
+
}
|
|
67
|
+
function listCwdAncestorNodeModulesDirs(cwd) {
|
|
68
|
+
const resolvedCwd = normalizePath(cwd);
|
|
69
|
+
const dirs = [];
|
|
70
|
+
let current = resolvedCwd;
|
|
71
|
+
while (true) {
|
|
72
|
+
const nodeModulesDir = path.join(current, "node_modules");
|
|
73
|
+
if (isDirectory(nodeModulesDir)) {
|
|
74
|
+
dirs.push(nodeModulesDir);
|
|
75
|
+
}
|
|
76
|
+
if (isFile(path.join(current, "package.json"))) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
const parent = path.dirname(current);
|
|
80
|
+
if (parent === current) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
current = parent;
|
|
84
|
+
}
|
|
85
|
+
return dirs;
|
|
86
|
+
}
|
|
87
|
+
function discoverNodeModulesDirs(cwd = process.cwd(), options) {
|
|
88
|
+
const explicit = options?.candidateDirs?.filter((dir) => isDirectory(dir)) ?? [];
|
|
89
|
+
if (explicit.length > 0) {
|
|
90
|
+
return uniqueResolvedPathsInOrder(explicit);
|
|
91
|
+
}
|
|
92
|
+
return uniqueResolvedPathsInOrder([
|
|
93
|
+
...listInstalledPackageNodeModulesDirs(),
|
|
94
|
+
...listCwdAncestorNodeModulesDirs(cwd)
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
function discoverProjectRoots(cwd = process.cwd(), options) {
|
|
98
|
+
const roots = discoverNodeModulesDirs(cwd, options?.nodeModulesDirs ? { candidateDirs: options.nodeModulesDirs } : void 0).map((nodeModulesDir) => path.dirname(nodeModulesDir));
|
|
99
|
+
return uniqueResolvedPathsInOrder([cwd, ...roots]);
|
|
100
|
+
}
|
|
101
|
+
function listTopLevelPackages(nodeModulesDir) {
|
|
102
|
+
const entries = readdirSync(nodeModulesDir, { withFileTypes: true }).filter((entry) => !entry.name.startsWith(".") && entry.name !== ".bin" && entry.name !== ".pnpm").sort((left, right) => left.name.localeCompare(right.name));
|
|
103
|
+
const packages = [];
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
const entryPath = path.join(nodeModulesDir, entry.name);
|
|
106
|
+
if (entry.name.startsWith("@")) {
|
|
107
|
+
if (!isDirectory(entryPath)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const scopedEntries = readdirSync(entryPath, { withFileTypes: true }).sort(
|
|
111
|
+
(left, right) => left.name.localeCompare(right.name)
|
|
112
|
+
);
|
|
113
|
+
for (const scopedEntry of scopedEntries) {
|
|
114
|
+
const packageName = `${entry.name}/${scopedEntry.name}`;
|
|
115
|
+
const packagePath = path.join(entryPath, scopedEntry.name);
|
|
116
|
+
if (!isDirectory(packagePath)) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
packages.push({ name: packageName, dir: packagePath });
|
|
120
|
+
}
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (!isDirectory(entryPath)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
packages.push({ name: entry.name, dir: entryPath });
|
|
127
|
+
}
|
|
128
|
+
return packages;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/chat/plugins/package-discovery.ts
|
|
132
|
+
import { createRequire } from "module";
|
|
133
|
+
import path2 from "path";
|
|
134
|
+
var require2 = createRequire(import.meta.url);
|
|
135
|
+
function normalizeForGlob(targetPath) {
|
|
136
|
+
return targetPath.split(path2.sep).join("/");
|
|
137
|
+
}
|
|
138
|
+
function uniqueStringsInOrder(values) {
|
|
139
|
+
const seen = /* @__PURE__ */ new Set();
|
|
140
|
+
const resolved = [];
|
|
141
|
+
for (const value of values) {
|
|
142
|
+
if (seen.has(value)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
seen.add(value);
|
|
146
|
+
resolved.push(value);
|
|
147
|
+
}
|
|
148
|
+
return resolved;
|
|
149
|
+
}
|
|
150
|
+
function pathWithinCwd(cwd, targetPath) {
|
|
151
|
+
const relative = path2.relative(cwd, targetPath);
|
|
152
|
+
if (!relative || relative.startsWith("..") || path2.isAbsolute(relative)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return `./${normalizeForGlob(relative)}`;
|
|
156
|
+
}
|
|
157
|
+
function parseRuntimeConfiguredPackageNames(value) {
|
|
158
|
+
if (!Array.isArray(value)) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const parsed = value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
162
|
+
return uniqueStringsInOrder(parsed.map((entry) => entry.trim()));
|
|
163
|
+
}
|
|
164
|
+
function readNextRuntimeConfiguredPackageNames() {
|
|
165
|
+
try {
|
|
166
|
+
const nextConfigModule = require2("next/config");
|
|
167
|
+
const getConfig = nextConfigModule.default;
|
|
168
|
+
if (typeof getConfig !== "function") {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const runtimeConfig = getConfig();
|
|
172
|
+
return parseRuntimeConfiguredPackageNames(runtimeConfig?.serverRuntimeConfig?.juniorPluginPackages) ?? [];
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function findContainingNodeModulesDir(targetPath) {
|
|
178
|
+
let current = path2.resolve(targetPath);
|
|
179
|
+
while (true) {
|
|
180
|
+
if (path2.basename(current) === "node_modules") {
|
|
181
|
+
return current;
|
|
182
|
+
}
|
|
183
|
+
const parent = path2.dirname(current);
|
|
184
|
+
if (parent === current) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
current = parent;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function resolvePackageDirFromName(packageName, candidateNodeModulesDirs) {
|
|
191
|
+
for (const nodeModulesDir of candidateNodeModulesDirs) {
|
|
192
|
+
const packageDir = path2.join(nodeModulesDir, ...packageName.split("/"));
|
|
193
|
+
if (isDirectory(packageDir)) {
|
|
194
|
+
return {
|
|
195
|
+
dir: path2.resolve(packageDir),
|
|
196
|
+
nodeModulesDir: path2.resolve(nodeModulesDir)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const packageJsonPath = require2.resolve(`${packageName}/package.json`);
|
|
202
|
+
const dir = path2.dirname(packageJsonPath);
|
|
203
|
+
const nodeModulesDir = findContainingNodeModulesDir(dir);
|
|
204
|
+
if (!nodeModulesDir) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
dir: path2.resolve(dir),
|
|
209
|
+
nodeModulesDir: path2.resolve(nodeModulesDir)
|
|
210
|
+
};
|
|
211
|
+
} catch {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function discoverDeclaredPackages(packageNames, candidateNodeModulesDirs) {
|
|
216
|
+
const discovered = [];
|
|
217
|
+
const seenPackageNames = /* @__PURE__ */ new Set();
|
|
218
|
+
const seenPackageDirs = /* @__PURE__ */ new Set();
|
|
219
|
+
for (const packageName of packageNames) {
|
|
220
|
+
const resolved = resolvePackageDirFromName(packageName, candidateNodeModulesDirs);
|
|
221
|
+
if (!resolved) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (seenPackageNames.has(packageName) || seenPackageDirs.has(resolved.dir)) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const hasRootPluginManifest = isFile(path2.join(resolved.dir, "plugin.yaml"));
|
|
228
|
+
const hasPluginsDir = isDirectory(path2.join(resolved.dir, "plugins"));
|
|
229
|
+
const hasSkillsDir = isDirectory(path2.join(resolved.dir, "skills"));
|
|
230
|
+
if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
seenPackageNames.add(packageName);
|
|
234
|
+
seenPackageDirs.add(resolved.dir);
|
|
235
|
+
discovered.push({
|
|
236
|
+
name: packageName,
|
|
237
|
+
dir: resolved.dir,
|
|
238
|
+
nodeModulesDir: resolved.nodeModulesDir,
|
|
239
|
+
hasRootPluginManifest,
|
|
240
|
+
hasPluginsDir,
|
|
241
|
+
hasSkillsDir
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return discovered;
|
|
245
|
+
}
|
|
246
|
+
function discoverInstalledJuniorContentPackages(cwd = process.cwd(), nodeModulesDirs, packageNames) {
|
|
247
|
+
const resolvedCwd = path2.resolve(cwd);
|
|
248
|
+
const candidateNodeModulesDirs = nodeModulesDirs ?? discoverNodeModulesDirs(resolvedCwd);
|
|
249
|
+
const configuredPackageNames = packageNames ?? readNextRuntimeConfiguredPackageNames();
|
|
250
|
+
const declaredPackages = discoverDeclaredPackages(configuredPackageNames ?? [], candidateNodeModulesDirs);
|
|
251
|
+
const useFallbackScan = configuredPackageNames === null;
|
|
252
|
+
const discovered = [...declaredPackages];
|
|
253
|
+
const seenPackageNames = /* @__PURE__ */ new Set();
|
|
254
|
+
const seenPackageDirs = /* @__PURE__ */ new Set();
|
|
255
|
+
for (const pkg of declaredPackages) {
|
|
256
|
+
seenPackageNames.add(pkg.name);
|
|
257
|
+
seenPackageDirs.add(pkg.dir);
|
|
258
|
+
}
|
|
259
|
+
if (!useFallbackScan) {
|
|
260
|
+
return discovered;
|
|
261
|
+
}
|
|
262
|
+
for (const nodeModulesDir of candidateNodeModulesDirs) {
|
|
263
|
+
for (const pkg of listTopLevelPackages(nodeModulesDir)) {
|
|
264
|
+
const resolvedDir = path2.resolve(pkg.dir);
|
|
265
|
+
if (seenPackageNames.has(pkg.name) || seenPackageDirs.has(resolvedDir)) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
seenPackageNames.add(pkg.name);
|
|
269
|
+
seenPackageDirs.add(resolvedDir);
|
|
270
|
+
const hasRootPluginManifest = isFile(path2.join(resolvedDir, "plugin.yaml"));
|
|
271
|
+
const hasPluginsDir = isDirectory(path2.join(resolvedDir, "plugins"));
|
|
272
|
+
const hasSkillsDir = isDirectory(path2.join(resolvedDir, "skills"));
|
|
273
|
+
if (!hasRootPluginManifest && !hasPluginsDir && !hasSkillsDir) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
discovered.push({
|
|
277
|
+
name: pkg.name,
|
|
278
|
+
dir: resolvedDir,
|
|
279
|
+
nodeModulesDir: path2.resolve(nodeModulesDir),
|
|
280
|
+
hasRootPluginManifest,
|
|
281
|
+
hasPluginsDir,
|
|
282
|
+
hasSkillsDir
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return discovered;
|
|
287
|
+
}
|
|
288
|
+
function discoverInstalledPluginPackageContent(cwd = process.cwd(), options) {
|
|
289
|
+
const resolvedCwd = path2.resolve(cwd);
|
|
290
|
+
const discoveredPackages = discoverInstalledJuniorContentPackages(resolvedCwd, options?.nodeModulesDirs, options?.packageNames);
|
|
291
|
+
const manifestRoots = [];
|
|
292
|
+
const skillRoots = [];
|
|
293
|
+
const tracingIncludes = [];
|
|
294
|
+
for (const pkg of discoveredPackages) {
|
|
295
|
+
const packagePathFromNodeModules = pathWithinCwd(resolvedCwd, path2.join(pkg.nodeModulesDir, ...pkg.name.split("/")));
|
|
296
|
+
if (pkg.hasRootPluginManifest) {
|
|
297
|
+
manifestRoots.push(pkg.dir);
|
|
298
|
+
if (packagePathFromNodeModules) {
|
|
299
|
+
tracingIncludes.push(`${packagePathFromNodeModules}/plugin.yaml`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (pkg.hasPluginsDir) {
|
|
303
|
+
manifestRoots.push(path2.join(pkg.dir, "plugins"));
|
|
304
|
+
if (packagePathFromNodeModules) {
|
|
305
|
+
tracingIncludes.push(`${packagePathFromNodeModules}/plugins/**/*`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (pkg.hasSkillsDir) {
|
|
309
|
+
skillRoots.push(path2.join(pkg.dir, "skills"));
|
|
310
|
+
if (packagePathFromNodeModules) {
|
|
311
|
+
tracingIncludes.push(`${packagePathFromNodeModules}/skills/**/*`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
packageNames: uniqueStringsInOrder(discoveredPackages.map((pkg) => pkg.name)),
|
|
317
|
+
manifestRoots: uniqueStringsInOrder(manifestRoots),
|
|
318
|
+
skillRoots: uniqueStringsInOrder(skillRoots),
|
|
319
|
+
tracingIncludes: uniqueStringsInOrder(tracingIncludes)
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export {
|
|
324
|
+
isDirectory,
|
|
325
|
+
discoverNodeModulesDirs,
|
|
326
|
+
discoverProjectRoots,
|
|
327
|
+
discoverInstalledPluginPackageContent
|
|
328
|
+
};
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/cli/init.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
function writeRouteModule(filePath, exportLine) {
|
|
5
|
+
fs.writeFileSync(filePath, `${exportLine}
|
|
6
|
+
export const runtime = "nodejs";
|
|
7
|
+
`);
|
|
8
|
+
}
|
|
9
|
+
function writeWrapperFiles(targetDir) {
|
|
10
|
+
const routeDir = path.join(targetDir, "app", "api", "[...path]");
|
|
11
|
+
fs.mkdirSync(routeDir, { recursive: true });
|
|
12
|
+
writeRouteModule(path.join(routeDir, "route.js"), 'export { GET, POST } from "@sentry/junior/handler";');
|
|
13
|
+
const queueRouteDir = path.join(targetDir, "app", "api", "queue", "callback");
|
|
14
|
+
fs.mkdirSync(queueRouteDir, { recursive: true });
|
|
15
|
+
writeRouteModule(
|
|
16
|
+
path.join(queueRouteDir, "route.js"),
|
|
17
|
+
'export { POST } from "@sentry/junior/handlers/queue-callback";'
|
|
18
|
+
);
|
|
19
|
+
fs.mkdirSync(path.join(targetDir, "app"), { recursive: true });
|
|
20
|
+
fs.writeFileSync(
|
|
21
|
+
path.join(targetDir, "app", "layout.js"),
|
|
22
|
+
'export { default } from "@sentry/junior/app/layout";\n'
|
|
23
|
+
);
|
|
24
|
+
fs.writeFileSync(
|
|
25
|
+
path.join(targetDir, "next.config.mjs"),
|
|
26
|
+
'import { withJunior } from "@sentry/junior/config";\nexport default withJunior();\n'
|
|
27
|
+
);
|
|
28
|
+
fs.writeFileSync(
|
|
29
|
+
path.join(targetDir, "instrumentation.js"),
|
|
30
|
+
'export { register, onRequestError } from "@sentry/junior/instrumentation";\n'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
async function runInit(dir, log = console.log) {
|
|
34
|
+
const targetDir = dir.trim();
|
|
35
|
+
if (!targetDir) {
|
|
36
|
+
throw new Error("usage: junior init <dir>");
|
|
37
|
+
}
|
|
38
|
+
const target = path.resolve(targetDir);
|
|
39
|
+
if (fs.existsSync(target)) {
|
|
40
|
+
const stat = fs.statSync(target);
|
|
41
|
+
if (!stat.isDirectory()) {
|
|
42
|
+
throw new Error(`refusing to initialize non-directory path: ${target}`);
|
|
43
|
+
}
|
|
44
|
+
if (fs.readdirSync(target).length > 0) {
|
|
45
|
+
throw new Error(`refusing to initialize non-empty directory: ${target}`);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
fs.mkdirSync(target, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
const name = path.basename(target);
|
|
51
|
+
const pkg = {
|
|
52
|
+
name,
|
|
53
|
+
version: "0.1.0",
|
|
54
|
+
private: true,
|
|
55
|
+
type: "module",
|
|
56
|
+
scripts: {
|
|
57
|
+
dev: "next dev",
|
|
58
|
+
build: "next build",
|
|
59
|
+
start: "next start"
|
|
60
|
+
},
|
|
61
|
+
dependencies: {
|
|
62
|
+
"@sentry/junior": "latest",
|
|
63
|
+
next: "^16.0.0",
|
|
64
|
+
react: "^19.0.0",
|
|
65
|
+
"react-dom": "^19.0.0",
|
|
66
|
+
"@sentry/nextjs": "^10.0.0"
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
fs.writeFileSync(path.join(target, "package.json"), `${JSON.stringify(pkg, null, 2)}
|
|
70
|
+
`);
|
|
71
|
+
const dataDir = path.join(target, "app", "data");
|
|
72
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
73
|
+
fs.writeFileSync(path.join(dataDir, "SOUL.md"), `# ${name}
|
|
74
|
+
|
|
75
|
+
You are ${name}, a helpful assistant.
|
|
76
|
+
`);
|
|
77
|
+
const skillsDir = path.join(target, "app", "skills");
|
|
78
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
79
|
+
fs.writeFileSync(path.join(skillsDir, ".gitkeep"), "");
|
|
80
|
+
const pluginsDir = path.join(target, "app", "plugins");
|
|
81
|
+
fs.mkdirSync(pluginsDir, { recursive: true });
|
|
82
|
+
fs.writeFileSync(path.join(pluginsDir, ".gitkeep"), "");
|
|
83
|
+
fs.writeFileSync(path.join(target, ".gitignore"), ["node_modules/", ".next/", ".env", ".env.local", ""].join("\n"));
|
|
84
|
+
fs.writeFileSync(
|
|
85
|
+
path.join(target, ".env.example"),
|
|
86
|
+
[
|
|
87
|
+
"SLACK_BOT_TOKEN=",
|
|
88
|
+
"SLACK_SIGNING_SECRET=",
|
|
89
|
+
"JUNIOR_BOT_NAME=",
|
|
90
|
+
"AI_MODEL=",
|
|
91
|
+
"AI_FAST_MODEL=",
|
|
92
|
+
"REDIS_URL=",
|
|
93
|
+
"NEXT_PUBLIC_SENTRY_DSN=",
|
|
94
|
+
""
|
|
95
|
+
].join("\n")
|
|
96
|
+
);
|
|
97
|
+
writeWrapperFiles(target);
|
|
98
|
+
log(`Created ${name} at ${target}`);
|
|
99
|
+
log("");
|
|
100
|
+
log(` cd ${targetDir} && pnpm install && pnpm dev`);
|
|
101
|
+
log("");
|
|
102
|
+
}
|
|
103
|
+
export {
|
|
104
|
+
runInit
|
|
105
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const CLI_USAGE = "usage: junior init <dir>\n junior snapshot create";
|
|
2
|
+
interface CliHandlers {
|
|
3
|
+
runInit: (dir: string) => Promise<void>;
|
|
4
|
+
runSnapshotCreate: () => Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
interface CliIo {
|
|
7
|
+
error: (line: string) => void;
|
|
8
|
+
}
|
|
9
|
+
declare function runCli(argv: string[], handlers: CliHandlers, io?: CliIo): Promise<number>;
|
|
10
|
+
|
|
11
|
+
export { CLI_USAGE, runCli };
|
package/dist/cli/run.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/cli/run.ts
|
|
2
|
+
var CLI_USAGE = "usage: junior init <dir>\n junior snapshot create";
|
|
3
|
+
var DEFAULT_IO = {
|
|
4
|
+
error: console.error
|
|
5
|
+
};
|
|
6
|
+
async function runCli(argv, handlers, io = DEFAULT_IO) {
|
|
7
|
+
const [command, subcommand, ...rest] = argv;
|
|
8
|
+
if (command === "init") {
|
|
9
|
+
if (!subcommand || rest.length > 0) {
|
|
10
|
+
io.error(CLI_USAGE);
|
|
11
|
+
return 1;
|
|
12
|
+
}
|
|
13
|
+
await handlers.runInit(subcommand);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
if (command === "snapshot" && subcommand === "create") {
|
|
17
|
+
if (rest.length > 0) {
|
|
18
|
+
io.error(CLI_USAGE);
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
await handlers.runSnapshotCreate();
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
io.error(CLI_USAGE);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
CLI_USAGE,
|
|
29
|
+
runCli
|
|
30
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
disconnectStateAdapter,
|
|
3
|
+
resolveRuntimeDependencySnapshot
|
|
4
|
+
} from "../chunk-DPTR2FNH.js";
|
|
5
|
+
import "../chunk-PY4AI2GZ.js";
|
|
6
|
+
import "../chunk-SP6LV35L.js";
|
|
7
|
+
|
|
8
|
+
// src/cli/snapshot-warmup.ts
|
|
9
|
+
var DEFAULT_RUNTIME = "node22";
|
|
10
|
+
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
11
|
+
function progressMessage(phase) {
|
|
12
|
+
if (phase === "resolve_start") {
|
|
13
|
+
return "Resolving sandbox snapshot profile...";
|
|
14
|
+
}
|
|
15
|
+
if (phase === "cache_hit") {
|
|
16
|
+
return "Using cached sandbox snapshot.";
|
|
17
|
+
}
|
|
18
|
+
if (phase === "waiting_for_lock") {
|
|
19
|
+
return "Waiting for sandbox snapshot build lock...";
|
|
20
|
+
}
|
|
21
|
+
if (phase === "building_snapshot") {
|
|
22
|
+
return "Building sandbox snapshot...";
|
|
23
|
+
}
|
|
24
|
+
return "Sandbox snapshot build complete.";
|
|
25
|
+
}
|
|
26
|
+
async function runSnapshotCreate(log = console.log) {
|
|
27
|
+
const runtime = DEFAULT_RUNTIME;
|
|
28
|
+
const timeoutMs = DEFAULT_TIMEOUT_MS;
|
|
29
|
+
try {
|
|
30
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
31
|
+
const snapshot = await resolveRuntimeDependencySnapshot({
|
|
32
|
+
runtime,
|
|
33
|
+
timeoutMs,
|
|
34
|
+
onProgress: async (phase) => {
|
|
35
|
+
if (emitted.has(phase)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
emitted.add(phase);
|
|
39
|
+
log(progressMessage(phase));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const fields = [
|
|
43
|
+
`runtime=${runtime}`,
|
|
44
|
+
`resolve_outcome=${snapshot.resolveOutcome}`,
|
|
45
|
+
`cache_hit=${snapshot.cacheHit}`,
|
|
46
|
+
`dependency_count=${snapshot.dependencyCount}`,
|
|
47
|
+
...snapshot.profileHash ? [`profile_hash=${snapshot.profileHash}`] : [],
|
|
48
|
+
...snapshot.snapshotId ? [`snapshot_id=${snapshot.snapshotId}`] : [],
|
|
49
|
+
...snapshot.rebuildReason ? [`rebuild_reason=${snapshot.rebuildReason}`] : []
|
|
50
|
+
];
|
|
51
|
+
log(`Sandbox snapshot create complete: ${fields.join(" ")}`);
|
|
52
|
+
} finally {
|
|
53
|
+
await disconnectStateAdapter();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
runSnapshotCreate
|
|
58
|
+
};
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles `POST /api/queue/callback` for asynchronous thread processing.
|
|
3
|
+
*
|
|
4
|
+
* Keep this route as a dedicated handler in app code. The catch-all router can
|
|
5
|
+
* mirror this path for local/dev parity, but production queue delivery should
|
|
6
|
+
* always target the dedicated endpoint.
|
|
7
|
+
*/
|
|
1
8
|
declare function POST(request: Request): Promise<Response>;
|
|
2
9
|
|
|
3
10
|
export { POST };
|