jeopi-cli 16.4.2 → 16.4.3
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/CHANGELOG.md +74 -0
- package/dist/cli.js +3179 -3140
- package/dist/types/advisor/config.d.ts +4 -3
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/update-cli.d.ts +4 -1
- package/dist/types/cli/usage-error.d.ts +4 -0
- package/dist/types/commit/agentic/agent.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +7 -1
- package/dist/types/config/settings-schema.d.ts +3 -3
- package/dist/types/eval/py/tool-bridge.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/internal-urls/memory-protocol.d.ts +6 -6
- package/dist/types/internal-urls/types.d.ts +7 -0
- package/dist/types/irc/bus.d.ts +4 -0
- package/dist/types/lsp/deferred-diagnostics.d.ts +11 -0
- package/dist/types/modes/components/move-overlay.d.ts +1 -1
- package/dist/types/modes/components/plan-review-overlay.d.ts +2 -0
- package/dist/types/modes/components/welcome.d.ts +4 -0
- package/dist/types/modes/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/modes/orchestrate.d.ts +1 -1
- package/dist/types/modes/ultrathink.d.ts +1 -1
- package/dist/types/modes/workflow.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +5 -0
- package/dist/types/session/auth-broker-config.d.ts +2 -2
- package/dist/types/tools/bash-skill-urls.d.ts +3 -2
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +3 -1
- package/dist/types/tools/browser/cmux/rpc.d.ts +20 -0
- package/dist/types/tools/browser/launch.d.ts +1 -0
- package/dist/types/tools/browser/run-cancellation.d.ts +17 -2
- package/dist/types/tools/browser/run-output.d.ts +25 -0
- package/dist/types/tools/browser/tab-worker.d.ts +22 -0
- package/dist/types/utils/changelog.d.ts +35 -1
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +13 -0
- package/src/advisor/__tests__/config.test.ts +36 -0
- package/src/advisor/config.ts +11 -8
- package/src/autolearn/controller.ts +14 -2
- package/src/cli/args.ts +12 -0
- package/src/cli/flag-tables.ts +21 -7
- package/src/cli/update-cli.ts +63 -13
- package/src/cli/usage-error.ts +7 -0
- package/src/commands/acp.ts +11 -2
- package/src/commands/launch.ts +12 -3
- package/src/commit/agentic/agent.ts +4 -0
- package/src/commit/agentic/index.ts +46 -21
- package/src/config/model-resolver.ts +24 -6
- package/src/config/settings-schema.ts +3 -3
- package/src/edit/index.ts +10 -76
- package/src/edit/renderer.ts +13 -10
- package/src/eval/__tests__/agent-bridge.test.ts +19 -14
- package/src/eval/__tests__/bridge-timeout.test.ts +60 -0
- package/src/eval/executor-base.ts +84 -7
- package/src/eval/js/shared/rewrite-imports.ts +31 -13
- package/src/eval/py/tool-bridge.ts +13 -14
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/ttsr.ts +0 -3
- package/src/extensibility/custom-tools/loader.ts +70 -37
- package/src/extensibility/custom-tools/types.ts +3 -0
- package/src/extensibility/extensions/runner.ts +3 -0
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/plugins/manager.ts +21 -0
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/internal-urls/memory-protocol.ts +13 -8
- package/src/internal-urls/skill-protocol.ts +1 -1
- package/src/internal-urls/types.ts +7 -0
- package/src/irc/bus.ts +48 -18
- package/src/lsp/client.ts +7 -1
- package/src/lsp/deferred-diagnostics.ts +66 -0
- package/src/main.ts +13 -13
- package/src/mcp/tool-bridge.ts +57 -6
- package/src/mcp/transports/stdio.test.ts +45 -1
- package/src/mcp/transports/stdio.ts +6 -3
- package/src/modes/acp/acp-agent.ts +73 -2
- package/src/modes/acp/acp-event-mapper.ts +5 -0
- package/src/modes/acp/acp-mode.ts +11 -0
- package/src/modes/components/__tests__/move-overlay.test.ts +16 -1
- package/src/modes/components/advisor-config.ts +15 -7
- package/src/modes/components/move-overlay.ts +2 -3
- package/src/modes/components/plan-review-overlay.ts +7 -0
- package/src/modes/components/tips.txt +1 -1
- package/src/modes/components/welcome.ts +13 -14
- package/src/modes/controllers/command-controller.ts +8 -10
- package/src/modes/controllers/event-controller.ts +17 -30
- package/src/modes/controllers/input-controller.ts +9 -6
- package/src/modes/controllers/selector-controller.ts +3 -2
- package/src/modes/controllers/tan-command-controller.ts +40 -1
- package/src/modes/interactive-mode.ts +13 -0
- package/src/modes/magic-keyword-boundary.ts +23 -0
- package/src/modes/orchestrate.ts +6 -5
- package/src/modes/print-mode.ts +9 -0
- package/src/modes/ultrathink.ts +6 -5
- package/src/modes/workflow.ts +5 -4
- package/src/prompts/system/eager-task.md +2 -2
- package/src/prompts/system/tan-context-switch.md +17 -0
- package/src/prompts/tools/browser.md +5 -5
- package/src/sdk.ts +3 -0
- package/src/session/agent-session.ts +172 -25
- package/src/session/auth-broker-config.ts +4 -4
- package/src/session/snapcompact-inline.ts +3 -19
- package/src/session/streaming-output.ts +40 -12
- package/src/slash-commands/builtin-registry.ts +8 -8
- package/src/task/executor.ts +8 -0
- package/src/tools/bash-skill-urls.ts +7 -4
- package/src/tools/bash.ts +30 -22
- package/src/tools/browser/cmux/cmux-tab.ts +49 -50
- package/src/tools/browser/cmux/rpc.ts +50 -0
- package/src/tools/browser/launch.ts +8 -4
- package/src/tools/browser/run-cancellation.ts +44 -5
- package/src/tools/browser/run-output.ts +76 -0
- package/src/tools/browser/tab-worker.ts +280 -133
- package/src/tools/eval-render.ts +16 -14
- package/src/tools/glob.ts +20 -6
- package/src/tools/grep.ts +1 -0
- package/src/tools/image-gen.ts +3 -4
- package/src/tools/irc.ts +27 -13
- package/src/tools/read.ts +14 -7
- package/src/tools/write.ts +22 -5
- package/src/tools/yield.ts +29 -1
- package/src/utils/changelog.ts +106 -9
- package/src/utils/git.ts +0 -1
- package/src/utils/title-generator.ts +68 -7
- package/src/web/search/index.ts +14 -6
- package/src/web/search/providers/perplexity.ts +18 -2
|
@@ -15,6 +15,7 @@ export interface PyToolBridgeEntry {
|
|
|
15
15
|
toolSession: ToolSession;
|
|
16
16
|
signal?: AbortSignal;
|
|
17
17
|
emitStatus?: (event: JsStatusEvent) => void;
|
|
18
|
+
abortRequested?: () => boolean;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface PyToolBridgeInfo {
|
|
@@ -31,23 +32,21 @@ const registrations = new Map<string, PyToolBridgeEntry>();
|
|
|
31
32
|
let serverPromise: Promise<BridgeServer> | null = null;
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
|
-
* Forward a bridge call to {@link callSessionTool}
|
|
35
|
-
*
|
|
36
|
-
* to fully tear down.
|
|
35
|
+
* Forward a bridge call to {@link callSessionTool} while respecting eval abort
|
|
36
|
+
* shielding.
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* persistent state lost while the subagents were still winding down. Responding
|
|
46
|
-
* immediately on abort lets the kernel raise through the blocked call and settle
|
|
47
|
-
* cleanly (preserving state); the already-signaled call keeps tearing down in
|
|
48
|
-
* the background, its eventual result/rejection swallowed.
|
|
38
|
+
* Python invokes this bridge with blocking `urllib` requests from worker threads
|
|
39
|
+
* (each `agent()` / `tool.*` call). The base executor defers the registered
|
|
40
|
+
* signal while a bridge call is already paused so in-flight subagents can finish
|
|
41
|
+
* and persist output instead of being orphaned. Once an abort has been requested,
|
|
42
|
+
* later bridge calls are rejected before starting; once the shielded signal
|
|
43
|
+
* finally aborts, this handler still resolves the HTTP request promptly so the
|
|
44
|
+
* kernel can unwind without being hard-killed.
|
|
49
45
|
*/
|
|
50
46
|
async function callSessionToolPromptOnAbort(name: string, args: unknown, entry: PyToolBridgeEntry): Promise<unknown> {
|
|
47
|
+
if (entry.abortRequested?.()) {
|
|
48
|
+
throw new Error(`bridge call ${JSON.stringify(name)} aborted: eval cell was interrupted`);
|
|
49
|
+
}
|
|
51
50
|
const call = callSessionTool(name, args, {
|
|
52
51
|
session: entry.toolSession,
|
|
53
52
|
signal: entry.signal,
|
|
@@ -15,7 +15,6 @@ export const NON_INTERACTIVE_ENV: Readonly<Record<string, string>> = {
|
|
|
15
15
|
LESS: "FRX",
|
|
16
16
|
// Disable terminal features that can block the process.
|
|
17
17
|
TERM: "dumb",
|
|
18
|
-
GPG_TTY: "not a tty",
|
|
19
18
|
NO_COLOR: "1",
|
|
20
19
|
PYTHONUNBUFFERED: "1",
|
|
21
20
|
// Disable editor and terminal credential prompts.
|
package/src/export/ttsr.ts
CHANGED
|
@@ -447,9 +447,6 @@ export class TtsrManager {
|
|
|
447
447
|
strictness: AstMatchStrictness.Smart,
|
|
448
448
|
limit: 1,
|
|
449
449
|
});
|
|
450
|
-
if (result.parseErrors && result.parseErrors.length > 0) {
|
|
451
|
-
logger.debug("TTSR ast match reported parse errors", { parseErrors: result.parseErrors });
|
|
452
|
-
}
|
|
453
450
|
return result.totalMatches > 0;
|
|
454
451
|
} catch (error) {
|
|
455
452
|
logger.warn("TTSR ast match failed, treating as no match", {
|
|
@@ -24,23 +24,53 @@ import type { CustomToolAPI, CustomToolFactory, LoadedCustomTool, ToolLoadError
|
|
|
24
24
|
/**
|
|
25
25
|
* Load a single tool module using native Bun import.
|
|
26
26
|
*/
|
|
27
|
+
interface LoadToolResult {
|
|
28
|
+
tools: LoadedCustomTool[];
|
|
29
|
+
errors: ToolLoadError[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isLoadableCustomTool(value: unknown): value is LoadedCustomTool["tool"] {
|
|
33
|
+
return (
|
|
34
|
+
typeof value === "object" &&
|
|
35
|
+
value !== null &&
|
|
36
|
+
"name" in value &&
|
|
37
|
+
typeof value.name === "string" &&
|
|
38
|
+
value.name.length > 0 &&
|
|
39
|
+
"description" in value &&
|
|
40
|
+
typeof value.description === "string" &&
|
|
41
|
+
"parameters" in value &&
|
|
42
|
+
"execute" in value &&
|
|
43
|
+
typeof value.execute === "function"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function invalidToolError(path: string, index: number, source: ToolLoadError["source"]): ToolLoadError {
|
|
48
|
+
return {
|
|
49
|
+
path,
|
|
50
|
+
error: `Tool factory returned invalid tool at index ${index}: expected object with string name, string description, parameters, and execute function`,
|
|
51
|
+
source,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
27
55
|
async function loadTool(
|
|
28
56
|
toolPath: string,
|
|
29
57
|
cwd: string,
|
|
30
58
|
sharedApi: CustomToolAPI,
|
|
31
59
|
source?: { provider: string; providerName: string; level: "user" | "project" },
|
|
32
|
-
): Promise<
|
|
60
|
+
): Promise<LoadToolResult> {
|
|
33
61
|
const resolvedPath = resolvePath(toolPath, cwd);
|
|
34
62
|
|
|
35
63
|
// Skip declarative tool files (.md, .json) - these are metadata only, not executable modules
|
|
36
64
|
if (resolvedPath.endsWith(".md") || resolvedPath.endsWith(".json")) {
|
|
37
65
|
return {
|
|
38
|
-
tools:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
tools: [],
|
|
67
|
+
errors: [
|
|
68
|
+
{
|
|
69
|
+
path: toolPath,
|
|
70
|
+
error: "Declarative tool files (.md, .json) cannot be loaded as executable modules",
|
|
71
|
+
source,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
44
74
|
};
|
|
45
75
|
}
|
|
46
76
|
|
|
@@ -49,23 +79,32 @@ async function loadTool(
|
|
|
49
79
|
const factory = (module.default ?? module) as CustomToolFactory;
|
|
50
80
|
|
|
51
81
|
if (typeof factory !== "function") {
|
|
52
|
-
return { tools:
|
|
82
|
+
return { tools: [], errors: [{ path: toolPath, error: "Tool must export a default function", source }] };
|
|
53
83
|
}
|
|
54
84
|
|
|
55
|
-
const toolResult = await factory(sharedApi);
|
|
85
|
+
const toolResult: unknown = await factory(sharedApi);
|
|
56
86
|
const toolsArray = Array.isArray(toolResult) ? toolResult : [toolResult];
|
|
57
87
|
|
|
58
|
-
const loadedTools: LoadedCustomTool[] =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
tool
|
|
62
|
-
|
|
63
|
-
|
|
88
|
+
const loadedTools: LoadedCustomTool[] = [];
|
|
89
|
+
const errors: ToolLoadError[] = [];
|
|
90
|
+
for (const [index, tool] of toolsArray.entries()) {
|
|
91
|
+
if (!isLoadableCustomTool(tool)) {
|
|
92
|
+
errors.push(invalidToolError(toolPath, index, source));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
loadedTools.push({
|
|
97
|
+
path: toolPath,
|
|
98
|
+
resolvedPath,
|
|
99
|
+
tool,
|
|
100
|
+
source,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
64
103
|
|
|
65
|
-
return { tools: loadedTools,
|
|
104
|
+
return { tools: loadedTools, errors };
|
|
66
105
|
} catch (err) {
|
|
67
106
|
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
-
return { tools:
|
|
107
|
+
return { tools: [], errors: [{ path: toolPath, error: `Failed to load tool: ${message}`, source }] };
|
|
69
108
|
}
|
|
70
109
|
}
|
|
71
110
|
|
|
@@ -129,28 +168,22 @@ export class CustomToolLoader {
|
|
|
129
168
|
|
|
130
169
|
async load(pathsWithSources: ToolPathWithSource[]): Promise<void> {
|
|
131
170
|
for (const { path: toolPath, source } of pathsWithSources) {
|
|
132
|
-
const { tools: loadedTools,
|
|
171
|
+
const { tools: loadedTools, errors } = await loadTool(toolPath, this.#sharedApi.cwd, this.#sharedApi, source);
|
|
172
|
+
this.errors.push(...errors);
|
|
133
173
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.errors.push({
|
|
144
|
-
path: toolPath,
|
|
145
|
-
error: `Tool name "${loadedTool.tool.name}" conflicts with existing tool`,
|
|
146
|
-
source,
|
|
147
|
-
});
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.#seenNames.add(loadedTool.tool.name);
|
|
152
|
-
this.tools.push(loadedTool);
|
|
174
|
+
for (const loadedTool of loadedTools) {
|
|
175
|
+
// Check for name conflicts
|
|
176
|
+
if (this.#seenNames.has(loadedTool.tool.name)) {
|
|
177
|
+
this.errors.push({
|
|
178
|
+
path: toolPath,
|
|
179
|
+
error: `Tool name "${loadedTool.tool.name}" conflicts with existing tool`,
|
|
180
|
+
source,
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
153
183
|
}
|
|
184
|
+
|
|
185
|
+
this.#seenNames.add(loadedTool.tool.name);
|
|
186
|
+
this.tools.push(loadedTool);
|
|
154
187
|
}
|
|
155
188
|
}
|
|
156
189
|
}
|
|
@@ -24,6 +24,7 @@ import type { Settings } from "../../config/settings";
|
|
|
24
24
|
import type { ExecOptions, ExecResult } from "../../exec/exec";
|
|
25
25
|
import type { HookUIContext } from "../../extensibility/hooks/types";
|
|
26
26
|
import type * as PiCodingAgent from "../../index";
|
|
27
|
+
import type { LocalProtocolOptions } from "../../internal-urls/local-protocol";
|
|
27
28
|
import type { Theme } from "../../modes/theme/theme";
|
|
28
29
|
import type { ReadonlySessionManager } from "../../session/session-manager";
|
|
29
30
|
import type { TodoItem } from "../../tools/todo";
|
|
@@ -96,6 +97,8 @@ export interface CustomToolContext {
|
|
|
96
97
|
settings?: Settings;
|
|
97
98
|
/** Fetch implementation for outbound HTTP; defaults to global fetch when omitted. */
|
|
98
99
|
fetch?: FetchImpl;
|
|
100
|
+
/** Calling session's `local://` root mapping for tools that bridge out of the OMP process. */
|
|
101
|
+
localProtocolOptions?: LocalProtocolOptions;
|
|
99
102
|
/** Whether to auto-approve all destructive tool operations (--auto-approve CLI flag) */
|
|
100
103
|
autoApprove?: boolean;
|
|
101
104
|
}
|
|
@@ -7,6 +7,7 @@ import type { KeyId } from "jeopi-tui";
|
|
|
7
7
|
import { logger } from "jeopi-utils";
|
|
8
8
|
import type { ModelRegistry } from "../../config/model-registry";
|
|
9
9
|
import type { Settings } from "../../config/settings";
|
|
10
|
+
import type { LocalProtocolOptions } from "../../internal-urls/local-protocol";
|
|
10
11
|
import type { MemoryRuntimeContext } from "../../memory-backend";
|
|
11
12
|
import { type Theme, theme } from "../../modes/theme/theme";
|
|
12
13
|
import type { SessionManager } from "../../session/session-manager";
|
|
@@ -255,6 +256,7 @@ export class ExtensionRunner {
|
|
|
255
256
|
private readonly modelRegistry: ModelRegistry,
|
|
256
257
|
getMemory?: () => MemoryRuntimeContext | undefined,
|
|
257
258
|
private readonly settings?: Settings,
|
|
259
|
+
private readonly localProtocolOptions?: LocalProtocolOptions,
|
|
258
260
|
) {
|
|
259
261
|
this.#uiContext = noOpUIContext;
|
|
260
262
|
this.#getMemoryFn = getMemory;
|
|
@@ -537,6 +539,7 @@ export class ExtensionRunner {
|
|
|
537
539
|
hasPendingMessages: () => this.#hasPendingMessagesFn(),
|
|
538
540
|
shutdown: () => this.#shutdownHandler(),
|
|
539
541
|
getSystemPrompt: () => this.#getSystemPromptFn(),
|
|
542
|
+
localProtocolOptions: this.localProtocolOptions,
|
|
540
543
|
memory: this.#getMemoryFn?.(),
|
|
541
544
|
};
|
|
542
545
|
}
|
|
@@ -42,6 +42,7 @@ import type { PythonResult } from "../../eval/py/executor";
|
|
|
42
42
|
import type { BashResult } from "../../exec/bash-executor";
|
|
43
43
|
import type { ExecOptions, ExecResult } from "../../exec/exec";
|
|
44
44
|
import type * as PiCodingAgent from "../../index";
|
|
45
|
+
import type { LocalProtocolOptions } from "../../internal-urls/local-protocol";
|
|
45
46
|
import type { MemoryRuntimeContext } from "../../memory-backend";
|
|
46
47
|
import type { CustomEditor } from "../../modes/components/custom-editor";
|
|
47
48
|
import type { Theme } from "../../modes/theme/theme";
|
|
@@ -346,6 +347,8 @@ export interface ExtensionContext {
|
|
|
346
347
|
sessionManager: ReadonlySessionManager;
|
|
347
348
|
/** Model registry for API key resolution */
|
|
348
349
|
modelRegistry: ModelRegistry;
|
|
350
|
+
/** Calling session's `local://` root mapping for external tool bridges. */
|
|
351
|
+
localProtocolOptions?: LocalProtocolOptions;
|
|
349
352
|
/** Current model (may be undefined) */
|
|
350
353
|
model: Model | undefined;
|
|
351
354
|
/** Read-only model query facade: list / current / resolve / family. */
|
|
@@ -212,6 +212,16 @@ export class PluginManager {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
async #removeDependencyEntry(pkgJsonPath: string, name: string): Promise<void> {
|
|
216
|
+
const pkgJson: { dependencies?: Record<string, string>; [key: string]: unknown } =
|
|
217
|
+
await Bun.file(pkgJsonPath).json();
|
|
218
|
+
if (!pkgJson.dependencies || !(name in pkgJson.dependencies)) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
delete pkgJson.dependencies[name];
|
|
222
|
+
await Bun.write(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
223
|
+
}
|
|
224
|
+
|
|
215
225
|
#collectInstalledNames(deps: Record<string, string>, config: PluginRuntimeConfig): Set<string> {
|
|
216
226
|
const installedNames = new Set<string>();
|
|
217
227
|
for (const name of Object.keys(deps)) {
|
|
@@ -451,6 +461,17 @@ export class PluginManager {
|
|
|
451
461
|
// validation throws.
|
|
452
462
|
let actualName: string | undefined;
|
|
453
463
|
try {
|
|
464
|
+
// Bun treats a dependency replacement from `repo#old-ref` to the same
|
|
465
|
+
// package at `repo`/`repo#new-ref` as a self-edge and bails with
|
|
466
|
+
// DependencyLoop. Remove only the stale manifest edge; rollback restores
|
|
467
|
+
// the original package.json and node_modules snapshot on failure.
|
|
468
|
+
if (gitSource && existingActualName) {
|
|
469
|
+
const installedSource = parseGitUrl(depsBefore[existingActualName] ?? "");
|
|
470
|
+
if (installedSource && installedSource.ref !== gitSource.ref) {
|
|
471
|
+
await this.#removeDependencyEntry(pkgJsonPath, existingActualName);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
454
475
|
// Step 1: write the spec into plugins/package.json + node_modules.
|
|
455
476
|
const installProc = Bun.spawn(["bun", "install", packageInstallSpec], {
|
|
456
477
|
cwd: getPluginsDir(),
|