Skip to content

Commit 6d0a9e4

Browse files
committed
bump version
1 parent 509027b commit 6d0a9e4

9 files changed

Lines changed: 224 additions & 18 deletions

File tree

executor/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ executor web
8383
Uninstall:
8484

8585
```bash
86-
bash executor/uninstall --yes
86+
executor uninstall --yes
8787
```
8888

8989
Default managed-runtime ports:

executor/apps/web/src/components/tools/view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export function ToolsView({
164164
{debug ? (
165165
<div className="space-y-0.5">
166166
<p className="text-[10px] font-mono text-muted-foreground/90">
167-
debug mode={debug.mode} · cacheHit={String(debug.cacheHit)} · cacheFresh={String(debug.cacheFresh)} · duration={debug.durationMs}ms · sources={debug.normalizedSourceCount}/{debug.sourceCount}
167+
debug mode={debug.mode} · cacheHit={String(debug.cacheHit)} · cacheFresh={String(debug.cacheFresh)} · skipCacheRead={String(debug.skipCacheRead)} · duration={debug.durationMs}ms · sources={debug.normalizedSourceCount}/{debug.sourceCount}
168168
{debug.timedOutSources.length > 0 ? ` · timedOut=${debug.timedOutSources.join(",")}` : " · timedOut=none"}
169169
</p>
170170
<p className="text-[10px] font-mono text-muted-foreground/80 truncate" title={debug.trace.join(" | ")}>

executor/apps/web/src/hooks/use-workspace-tools.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface WorkspaceToolsQueryResult {
2323
mode: "cache-fresh" | "cache-stale" | "rebuild";
2424
includeDts: boolean;
2525
sourceTimeoutMs: number | null;
26+
skipCacheRead: boolean;
2627
sourceCount: number;
2728
normalizedSourceCount: number;
2829
cacheHit: boolean;
@@ -96,6 +97,7 @@ export function useWorkspaceTools(context: WorkspaceContext | null) {
9697
durationMs: inventoryData.debug.durationMs,
9798
cacheHit: inventoryData.debug.cacheHit,
9899
cacheFresh: inventoryData.debug.cacheFresh,
100+
skipCacheRead: inventoryData.debug.skipCacheRead,
99101
sourceCount: inventoryData.debug.sourceCount,
100102
normalizedSourceCount: inventoryData.debug.normalizedSourceCount,
101103
timedOutSources: inventoryData.debug.timedOutSources,

executor/executor.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env bun
22

33
import fs from "node:fs/promises";
4+
import os from "node:os";
5+
import path from "node:path";
46
import { managedRuntimeDiagnostics, runManagedBackend, runManagedWeb } from "./packages/core/src/managed-runtime";
57

68
function printHelp(): void {
@@ -11,12 +13,14 @@ Usage:
1113
executor up [backend-args]
1214
executor backend <args>
1315
executor web [--port <number>]
16+
executor uninstall [--yes]
1417
1518
Commands:
1619
doctor Bootstrap and verify managed Convex backend runtime
1720
up Run managed backend and auto-bootstrap Convex functions
1821
backend Pass through arguments to managed convex-local-backend binary
1922
web Run packaged web UI (default port: 5312)
23+
uninstall Remove local managed runtime install
2024
`);
2125
}
2226

@@ -61,6 +65,73 @@ async function checkHttp(url: string): Promise<boolean> {
6165
}
6266
}
6367

68+
async function runUninstall(args: string[]): Promise<number> {
69+
let assumeYes = false;
70+
let index = 0;
71+
72+
while (index < args.length) {
73+
const arg = args[index];
74+
if (arg === "-y" || arg === "--yes") {
75+
assumeYes = true;
76+
index += 1;
77+
continue;
78+
}
79+
80+
if (arg === "-h" || arg === "--help") {
81+
console.log(`Usage:
82+
executor uninstall [--yes]
83+
84+
Options:
85+
-y, --yes Skip confirmation prompt
86+
-h, --help Show this help`);
87+
return 0;
88+
}
89+
90+
console.log(`Unknown option: ${arg}`);
91+
return 1;
92+
}
93+
94+
const installDir = Bun.env.EXECUTOR_INSTALL_DIR ?? path.join(os.homedir(), ".executor", "bin");
95+
const runtimeDir = Bun.env.EXECUTOR_RUNTIME_DIR ?? path.join(os.homedir(), ".executor", "runtime");
96+
const homeDir = Bun.env.EXECUTOR_HOME_DIR ?? path.join(os.homedir(), ".executor");
97+
98+
if (!assumeYes) {
99+
console.log("This will remove:");
100+
console.log(` - ${installDir}/executor`);
101+
console.log(` - ${runtimeDir}`);
102+
const response = prompt("Continue? [y/N] ");
103+
if (response === null || response.toLowerCase() !== "y") {
104+
console.log("Cancelled.");
105+
return 0;
106+
}
107+
}
108+
109+
await fs.rm(path.join(installDir, "executor"), { force: true });
110+
await fs.rm(runtimeDir, { recursive: true, force: true });
111+
112+
if (await pathExists(installDir)) {
113+
try {
114+
await fs.rmdir(installDir);
115+
} catch {
116+
// keep if it is not empty
117+
}
118+
}
119+
120+
if (await pathExists(homeDir)) {
121+
try {
122+
await fs.rmdir(homeDir);
123+
} catch {
124+
// keep if other files remain
125+
}
126+
}
127+
128+
console.log("Executor uninstall complete.");
129+
console.log("");
130+
console.log("If you previously added PATH manually, remove this line from your shell rc:");
131+
console.log(` export PATH=${installDir}:$PATH`);
132+
return 0;
133+
}
134+
64135
async function run(): Promise<void> {
65136
const [command, ...rest] = process.argv.slice(2);
66137

@@ -110,6 +181,11 @@ async function run(): Promise<void> {
110181
process.exit(exitCode);
111182
}
112183

184+
if (command === "uninstall") {
185+
const exitCode = await runUninstall(rest);
186+
process.exit(exitCode);
187+
}
188+
113189
throw new Error(`Unknown command: ${command}`);
114190
}
115191

executor/install

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ echo " executor up"
269269
echo " executor web # defaults to http://localhost:5312"
270270
echo ""
271271
echo "To uninstall later:"
272+
echo " executor uninstall --yes"
272273
echo " bash executor/uninstall --yes"
273274
echo ""
274275
show_star_prompt

executor/packages/convex/executorNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const listToolsWithWarnings = action({
4848
workspaceId: args.workspaceId,
4949
actorId: canonicalActorId,
5050
clientId: args.clientId,
51-
}, { includeDts: false, sourceTimeoutMs: 2_500, allowStaleOnMismatch: true });
51+
}, { includeDts: false, sourceTimeoutMs: 2_500, allowStaleOnMismatch: true, skipCacheRead: true });
5252

5353
if (inventory.warnings.some((warning) => warning.includes("showing previous results while refreshing"))) {
5454
try {

executor/packages/convex/runtime/workspace_tools.ts

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface WorkspaceToolsDebug {
3939
mode: "cache-fresh" | "cache-stale" | "rebuild";
4040
includeDts: boolean;
4141
sourceTimeoutMs: number | null;
42+
skipCacheRead: boolean;
4243
sourceCount: number;
4344
normalizedSourceCount: number;
4445
cacheHit: boolean;
@@ -52,6 +53,7 @@ interface GetWorkspaceToolsOptions {
5253
includeDts?: boolean;
5354
sourceTimeoutMs?: number;
5455
allowStaleOnMismatch?: boolean;
56+
skipCacheRead?: boolean;
5557
}
5658

5759
export interface WorkspaceToolInventory {
@@ -133,6 +135,7 @@ export async function getWorkspaceTools(
133135
const includeDts = options.includeDts ?? false;
134136
const sourceTimeoutMs = options.sourceTimeoutMs;
135137
const allowStaleOnMismatch = options.allowStaleOnMismatch ?? false;
138+
const skipCacheRead = options.skipCacheRead ?? false;
136139
const sources = (await ctx.runQuery(internal.database.listToolSources, { workspaceId }))
137140
.filter((source: { enabled: boolean }) => source.enabled);
138141
traceStep("listToolSources", listSourcesStartedAt);
@@ -141,10 +144,12 @@ export async function getWorkspaceTools(
141144
const debugBase: Omit<WorkspaceToolsDebug, "mode" | "normalizedSourceCount" | "cacheHit" | "cacheFresh" | "timedOutSources" | "durationMs" | "trace"> = {
142145
includeDts,
143146
sourceTimeoutMs: sourceTimeoutMs ?? null,
147+
skipCacheRead,
144148
sourceCount: sources.length,
145149
};
146150

147-
try {
151+
if (!skipCacheRead) {
152+
try {
148153
const cacheReadStartedAt = Date.now();
149154
const cacheEntry = await ctx.runQuery(internal.workspaceToolCache.getEntry, {
150155
workspaceId,
@@ -202,9 +207,12 @@ export async function getWorkspaceTools(
202207
}
203208
}
204209
}
205-
} catch (error) {
206-
const msg = error instanceof Error ? error.message : String(error);
207-
console.warn(`[executor] workspace tool cache read failed for '${workspaceId}': ${msg}`);
210+
} catch (error) {
211+
const msg = error instanceof Error ? error.message : String(error);
212+
console.warn(`[executor] workspace tool cache read failed for '${workspaceId}': ${msg}`);
213+
}
214+
} else {
215+
trace.push("cacheEntryLookup=skipped");
208216
}
209217

210218
const configs: ExternalToolSourceConfig[] = [];
@@ -364,13 +372,24 @@ export async function getWorkspaceTools(
364372
export async function loadWorkspaceToolInventoryForContext(
365373
ctx: ActionCtx,
366374
context: { workspaceId: Id<"workspaces">; actorId?: string; clientId?: string },
367-
options: { includeDts?: boolean; sourceTimeoutMs?: number; allowStaleOnMismatch?: boolean } = {},
375+
options: {
376+
includeDts?: boolean;
377+
sourceTimeoutMs?: number;
378+
allowStaleOnMismatch?: boolean;
379+
skipCacheRead?: boolean;
380+
} = {},
368381
): Promise<WorkspaceToolInventory> {
369382
const includeDts = options.includeDts ?? false;
370383
const sourceTimeoutMs = options.sourceTimeoutMs;
371384
const allowStaleOnMismatch = options.allowStaleOnMismatch;
385+
const skipCacheRead = options.skipCacheRead;
372386
const [result, policies] = await Promise.all([
373-
getWorkspaceTools(ctx, context.workspaceId, { includeDts, sourceTimeoutMs, allowStaleOnMismatch }),
387+
getWorkspaceTools(ctx, context.workspaceId, {
388+
includeDts,
389+
sourceTimeoutMs,
390+
allowStaleOnMismatch,
391+
skipCacheRead,
392+
}),
374393
ctx.runQuery(internal.database.listAccessPolicies, { workspaceId: context.workspaceId }),
375394
]);
376395
const typedPolicies = policies as AccessPolicyRecord[];
@@ -405,7 +424,12 @@ export async function loadWorkspaceToolInventoryForContext(
405424
export async function listToolsForContext(
406425
ctx: ActionCtx,
407426
context: { workspaceId: Id<"workspaces">; actorId?: string; clientId?: string },
408-
options: { includeDts?: boolean; sourceTimeoutMs?: number; allowStaleOnMismatch?: boolean } = {},
427+
options: {
428+
includeDts?: boolean;
429+
sourceTimeoutMs?: number;
430+
allowStaleOnMismatch?: boolean;
431+
skipCacheRead?: boolean;
432+
} = {},
409433
): Promise<ToolDescriptor[]> {
410434
const inventory = await loadWorkspaceToolInventoryForContext(ctx, context, options);
411435
return inventory.tools;
@@ -414,7 +438,12 @@ export async function listToolsForContext(
414438
export async function listToolsWithWarningsForContext(
415439
ctx: ActionCtx,
416440
context: { workspaceId: Id<"workspaces">; actorId?: string; clientId?: string },
417-
options: { includeDts?: boolean; sourceTimeoutMs?: number; allowStaleOnMismatch?: boolean } = {},
441+
options: {
442+
includeDts?: boolean;
443+
sourceTimeoutMs?: number;
444+
allowStaleOnMismatch?: boolean;
445+
skipCacheRead?: boolean;
446+
} = {},
418447
): Promise<{
419448
tools: ToolDescriptor[];
420449
warnings: string[];

executor/packages/core/src/managed-runtime-bootstrap.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,67 @@ async function generateSelfHostedAdminKey(info: ManagedRuntimeInfo): Promise<str
3333
return parsed.adminKey;
3434
}
3535

36+
async function hasAnyPath(paths: string[]): Promise<boolean> {
37+
for (const candidate of paths) {
38+
if (await pathExists(candidate)) {
39+
return true;
40+
}
41+
}
42+
return false;
43+
}
44+
45+
function getConfigCandidates(baseDir: string): string[] {
46+
return [
47+
path.join(baseDir, "convex.config.ts"),
48+
path.join(baseDir, "convex.config.js"),
49+
path.join(baseDir, "convex.config.mts"),
50+
path.join(baseDir, "convex.config.mjs"),
51+
path.join(baseDir, "convex.config.cts"),
52+
path.join(baseDir, "convex.config.cjs"),
53+
];
54+
}
55+
56+
async function getConfiguredFunctionsPath(candidate: string): Promise<string | null> {
57+
try {
58+
const raw = await fs.readFile(path.join(candidate, "convex.json"), "utf8");
59+
const parsed = JSON.parse(raw) as { functions?: unknown };
60+
if (typeof parsed.functions !== "string") {
61+
return null;
62+
}
63+
const value = parsed.functions.trim();
64+
return value.length > 0 ? value : null;
65+
} catch {
66+
return null;
67+
}
68+
}
69+
70+
async function hasConvexProjectConfig(candidate: string): Promise<boolean> {
71+
const convexJson = path.join(candidate, "convex.json");
72+
if (!(await pathExists(convexJson))) {
73+
return false;
74+
}
75+
76+
const legacyDir = path.join(candidate, "convex");
77+
const legacyMatches = await hasAnyPath(getConfigCandidates(legacyDir));
78+
if (legacyMatches) {
79+
return true;
80+
}
81+
82+
if (await hasAnyPath(getConfigCandidates(candidate))) {
83+
return true;
84+
}
85+
86+
const configuredFunctionsPath = await getConfiguredFunctionsPath(candidate);
87+
if (!configuredFunctionsPath) {
88+
return false;
89+
}
90+
91+
const resolvedFunctionsPath = path.isAbsolute(configuredFunctionsPath)
92+
? configuredFunctionsPath
93+
: path.resolve(candidate, configuredFunctionsPath);
94+
return await hasAnyPath(getConfigCandidates(resolvedFunctionsPath));
95+
}
96+
3697
async function findProjectDir(): Promise<string | null> {
3798
const roots = [
3899
Bun.env.EXECUTOR_PROJECT_DIR,
@@ -47,10 +108,7 @@ async function findProjectDir(): Promise<string | null> {
47108
}
48109

49110
for (const candidate of candidates) {
50-
const convexDir = path.join(candidate, "convex");
51-
const convexConfig = path.join(convexDir, "convex.config.ts");
52-
const convexJson = path.join(candidate, "convex.json");
53-
if ((await pathExists(convexDir)) && (await pathExists(convexConfig)) && (await pathExists(convexJson))) {
111+
if (await hasConvexProjectConfig(candidate)) {
54112
return candidate;
55113
}
56114
}

0 commit comments

Comments
 (0)