agent-sh 0.13.7 → 0.14.1
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 +7 -18
- package/dist/agent/agent-loop.d.ts +13 -17
- package/dist/agent/agent-loop.js +118 -224
- package/dist/agent/conversation-state.d.ts +1 -1
- package/dist/agent/events.d.ts +218 -0
- package/dist/agent/events.js +1 -0
- package/dist/agent/host-types.d.ts +20 -0
- package/dist/agent/index.d.ts +5 -9
- package/dist/agent/index.js +269 -167
- package/dist/{utils → agent}/llm-client.js +1 -0
- package/dist/agent/llm-facade.d.ts +13 -0
- package/dist/{utils → agent}/llm-facade.js +1 -1
- package/dist/agent/nuclear-form.d.ts +1 -1
- package/dist/agent/providers/deepseek.js +2 -5
- package/dist/agent/providers/openai-compatible.js +2 -2
- package/dist/agent/providers/openai.js +2 -5
- package/dist/agent/providers/openrouter.js +5 -5
- package/dist/agent/subagent.d.ts +1 -1
- package/dist/agent/tool-protocol.d.ts +1 -1
- package/dist/agent/tool-registry.d.ts +1 -1
- package/dist/agent/types.d.ts +2 -2
- package/dist/cli/args.js +3 -1
- package/dist/cli/auth/cli.js +11 -6
- package/dist/cli/auth/discover.d.ts +5 -0
- package/dist/cli/auth/discover.js +25 -0
- package/dist/cli/auth/keys.d.ts +5 -2
- package/dist/cli/auth/keys.js +22 -2
- package/dist/cli/index.d.ts +16 -0
- package/dist/cli/index.js +12 -2
- package/dist/cli/install.d.ts +1 -0
- package/dist/cli/install.js +86 -2
- package/dist/cli/subcommands.js +4 -1
- package/dist/core/event-bus.d.ts +28 -371
- package/dist/core/extension-loader.js +6 -6
- package/dist/core/index.d.ts +10 -29
- package/dist/core/index.js +32 -84
- package/dist/extensions/index.d.ts +2 -1
- package/dist/extensions/index.js +1 -1
- package/dist/extensions/slash-commands/events.d.ts +18 -0
- package/dist/extensions/slash-commands/events.js +1 -0
- package/dist/extensions/slash-commands/index.d.ts +15 -0
- package/dist/extensions/{slash-commands.js → slash-commands/index.js} +4 -3
- package/dist/shell/events.d.ts +85 -0
- package/dist/shell/events.js +1 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.js +6 -0
- package/dist/shell/tui-renderer.js +0 -1
- package/dist/utils/tool-interactive.js +4 -2
- package/examples/extensions/ash-acp-bridge/src/index.ts +2 -2
- package/examples/extensions/ashi/package.json +2 -2
- package/examples/extensions/ashi/src/cli.ts +4 -1
- package/examples/extensions/claude-code-bridge/index.ts +7 -2
- package/examples/extensions/claude-code-bridge/package.json +1 -1
- package/examples/extensions/ollama.ts +47 -42
- package/examples/extensions/opencode-bridge/README.md +4 -0
- package/examples/extensions/opencode-bridge/index.ts +208 -54
- package/examples/extensions/opencode-bridge/package.json +1 -1
- package/examples/extensions/pi-bridge/index.ts +3 -4
- package/examples/extensions/zai-coding-plan.ts +2 -6
- package/package.json +1 -1
- package/dist/extensions/slash-commands.d.ts +0 -2
- package/dist/utils/llm-facade.d.ts +0 -11
- /package/dist/{utils → agent}/llm-client.d.ts +0 -0
package/dist/agent/subagent.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Used by the subagent extension to delegate tasks from the main agent.
|
|
11
11
|
*/
|
|
12
12
|
import type { EventBus } from "../core/event-bus.js";
|
|
13
|
-
import type { LlmClient } from "
|
|
13
|
+
import type { LlmClient } from "./llm-client.js";
|
|
14
14
|
import type { ToolDefinition } from "./types.js";
|
|
15
15
|
export interface SubagentOptions {
|
|
16
16
|
/** LLM client to use. */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* The agent loop uses this interface uniformly so the rest of the code
|
|
10
10
|
* doesn't need to know which mode is active.
|
|
11
11
|
*/
|
|
12
|
-
import type { ChatCompletionTool } from "
|
|
12
|
+
import type { ChatCompletionTool } from "./llm-client.js";
|
|
13
13
|
import type { ToolDefinition } from "./types.js";
|
|
14
14
|
import type { ConversationState } from "./conversation-state.js";
|
|
15
15
|
export interface PendingToolCall {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ToolDefinition, ToolResult } from "./types.js";
|
|
2
|
-
import type { ChatCompletionTool } from "
|
|
2
|
+
import type { ChatCompletionTool } from "./llm-client.js";
|
|
3
3
|
import type { HandlerFunctions } from "../utils/handler-registry.js";
|
|
4
4
|
/**
|
|
5
5
|
* Registry for agent tools. Execution is routed through the named-handler
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -57,8 +57,8 @@ export interface InteractiveSession<T> {
|
|
|
57
57
|
render(width: number): string[];
|
|
58
58
|
/** Handle raw input. Call done(result) to finish the session. */
|
|
59
59
|
handleInput(data: string, done: (result: T) => void): void;
|
|
60
|
-
/**
|
|
61
|
-
onMount?(invalidate: () => void): void;
|
|
60
|
+
/** done() lets the session resolve itself from outside handleInput. */
|
|
61
|
+
onMount?(invalidate: () => void, done: (result: T) => void): void;
|
|
62
62
|
/** Called when session ends (cleanup). */
|
|
63
63
|
onUnmount?(): void;
|
|
64
64
|
}
|
package/dist/cli/args.js
CHANGED
|
@@ -3,7 +3,9 @@ const HELP_TEXT = `agent-sh — a shell-first terminal where AI is one keystroke
|
|
|
3
3
|
|
|
4
4
|
Usage: agent-sh [options]
|
|
5
5
|
agent-sh init [--force] Scaffold ~/.agent-sh/ (settings, examples, AGENTS.md)
|
|
6
|
-
agent-sh install <spec> [--force]
|
|
6
|
+
agent-sh install <spec> [--force] [--sync-deps]
|
|
7
|
+
Install an extension (bundled name, file:, npm:, github:)
|
|
8
|
+
--sync-deps rewrites a stale agent-sh pin to the host version
|
|
7
9
|
agent-sh uninstall <name> Remove an installed extension
|
|
8
10
|
agent-sh list List installed extensions
|
|
9
11
|
agent-sh auth login [provider] Store an API key for a built-in provider
|
package/dist/cli/auth/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as readline from "node:readline";
|
|
2
2
|
import { palette as p } from "../../utils/palette.js";
|
|
3
|
-
import { KNOWN_PROVIDERS, KEYS_PATH, loadKeysFile, saveKeysFile, resolveApiKey,
|
|
3
|
+
import { KNOWN_PROVIDERS, KEYS_PATH, loadKeysFile, saveKeysFile, resolveApiKey, listAllProvidersWithDiscovery, findProvider as findProviderById, } from "./keys.js";
|
|
4
4
|
export async function runAuth(args) {
|
|
5
5
|
const sub = args[0];
|
|
6
6
|
if (!sub || sub === "--help" || sub === "-h") {
|
|
@@ -16,7 +16,7 @@ export async function runAuth(args) {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
if (sub === "list" || sub === "ls" || sub === "status") {
|
|
19
|
-
runList();
|
|
19
|
+
await runList();
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
console.error(`agent-sh auth: unknown subcommand "${sub}"`);
|
|
@@ -90,8 +90,8 @@ function runLogout(providerArg) {
|
|
|
90
90
|
saveKeysFile(keys);
|
|
91
91
|
console.log(`${p.success}✓${p.reset} Removed ${id} key from ${KEYS_PATH}`);
|
|
92
92
|
}
|
|
93
|
-
function runList() {
|
|
94
|
-
const providers =
|
|
93
|
+
async function runList() {
|
|
94
|
+
const providers = await listAllProvidersWithDiscovery();
|
|
95
95
|
console.log("Provider key status:\n");
|
|
96
96
|
const idWidth = Math.max(...providers.map((p) => p.id.length));
|
|
97
97
|
for (const info of providers) {
|
|
@@ -105,6 +105,9 @@ function runList() {
|
|
|
105
105
|
if (resolved.key) {
|
|
106
106
|
console.log(` ${p.success}●${p.reset} ${padded} ${p.dim}(${sourceLabel(resolved.source, info)})${p.reset}${marker}`);
|
|
107
107
|
}
|
|
108
|
+
else if (info.noAuth) {
|
|
109
|
+
console.log(` ${p.success}●${p.reset} ${padded} ${p.dim}(no auth required)${p.reset}${marker}`);
|
|
110
|
+
}
|
|
108
111
|
else {
|
|
109
112
|
console.log(` ${p.muted}○${p.reset} ${padded} ${p.dim}(not configured)${p.reset}${marker}`);
|
|
110
113
|
}
|
|
@@ -117,13 +120,15 @@ async function pickProvider() {
|
|
|
117
120
|
console.error("agent-sh auth: no provider specified and stdin is not a TTY.");
|
|
118
121
|
return null;
|
|
119
122
|
}
|
|
120
|
-
const providers =
|
|
123
|
+
const providers = await listAllProvidersWithDiscovery();
|
|
121
124
|
console.log("Select a provider:");
|
|
122
125
|
providers.forEach((info, i) => {
|
|
123
126
|
const resolved = resolveApiKey(info.id);
|
|
124
127
|
const tag = resolved.key
|
|
125
128
|
? `${p.dim}(currently from ${sourceLabel(resolved.source, info)})${p.reset}`
|
|
126
|
-
:
|
|
129
|
+
: info.noAuth
|
|
130
|
+
? `${p.dim}(no auth required)${p.reset}`
|
|
131
|
+
: `${p.dim}(not configured)${p.reset}`;
|
|
127
132
|
const labelStr = info.custom
|
|
128
133
|
? `${p.dim}custom${p.reset}`
|
|
129
134
|
: info.unattached
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Bootstrap a throwaway core to enumerate provider ids extensions
|
|
2
|
+
* would register, so `auth list` shows ids the user hasn't keyed yet. */
|
|
3
|
+
import { createCore } from "../../core/index.js";
|
|
4
|
+
import { activateAgent } from "../../agent/index.js";
|
|
5
|
+
import { loadExtensions } from "../../core/extension-loader.js";
|
|
6
|
+
import { loadBuiltinExtensions } from "../../extensions/index.js";
|
|
7
|
+
import { getSettings } from "../../core/settings.js";
|
|
8
|
+
let cached = null;
|
|
9
|
+
export async function discoverExtensionProviders() {
|
|
10
|
+
if (cached)
|
|
11
|
+
return cached;
|
|
12
|
+
const core = createCore({});
|
|
13
|
+
try {
|
|
14
|
+
const ctx = core.extensionContext({ quit: () => { } });
|
|
15
|
+
activateAgent(ctx);
|
|
16
|
+
await loadBuiltinExtensions(ctx, getSettings().disabledBuiltins);
|
|
17
|
+
await loadExtensions(ctx).catch(() => { });
|
|
18
|
+
const { providers } = core.bus.emitPipe("agent:providers", { providers: [] });
|
|
19
|
+
cached = providers.map((p) => ({ id: p.id, noAuth: p.noAuth }));
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
core.kill();
|
|
24
|
+
}
|
|
25
|
+
}
|
package/dist/cli/auth/keys.d.ts
CHANGED
|
@@ -9,11 +9,14 @@ export interface ProviderAuthInfo {
|
|
|
9
9
|
/** True for ids only present in keys.json — likely owned by an extension
|
|
10
10
|
* that registers a provider at runtime. */
|
|
11
11
|
unattached?: boolean;
|
|
12
|
+
/** Auth UI shows "no auth required" instead of "not configured". */
|
|
13
|
+
noAuth?: boolean;
|
|
12
14
|
}
|
|
13
15
|
export declare const KNOWN_PROVIDERS: ProviderAuthInfo[];
|
|
14
|
-
/** Built-ins
|
|
15
|
-
* appear in keys.json (likely registered by an extension at runtime). */
|
|
16
|
+
/** Built-ins + settings + keys.json. Sync, no extension load. */
|
|
16
17
|
export declare function listAllProviders(): ProviderAuthInfo[];
|
|
18
|
+
/** Augments listAllProviders with extension-registered ids. */
|
|
19
|
+
export declare function listAllProvidersWithDiscovery(): Promise<ProviderAuthInfo[]>;
|
|
17
20
|
/** Resolve an id against known + settings entries only. Returns null for
|
|
18
21
|
* unattached or unknown ids — callers decide whether to accept them. */
|
|
19
22
|
export declare function findProvider(id: string): ProviderAuthInfo | null;
|
package/dist/cli/auth/keys.js
CHANGED
|
@@ -8,8 +8,7 @@ export const KNOWN_PROVIDERS = [
|
|
|
8
8
|
{ id: "openrouter", label: "OpenRouter", envVar: "OPENROUTER_API_KEY" },
|
|
9
9
|
{ id: "deepseek", label: "DeepSeek", envVar: "DEEPSEEK_API_KEY" },
|
|
10
10
|
];
|
|
11
|
-
/** Built-ins
|
|
12
|
-
* appear in keys.json (likely registered by an extension at runtime). */
|
|
11
|
+
/** Built-ins + settings + keys.json. Sync, no extension load. */
|
|
13
12
|
export function listAllProviders() {
|
|
14
13
|
const out = [...KNOWN_PROVIDERS];
|
|
15
14
|
const seen = new Set(out.map((p) => p.id));
|
|
@@ -28,6 +27,27 @@ export function listAllProviders() {
|
|
|
28
27
|
}
|
|
29
28
|
return out;
|
|
30
29
|
}
|
|
30
|
+
/** Augments listAllProviders with extension-registered ids. */
|
|
31
|
+
export async function listAllProvidersWithDiscovery() {
|
|
32
|
+
const out = listAllProviders();
|
|
33
|
+
const byId = new Map(out.map((p) => [p.id, p]));
|
|
34
|
+
const { discoverExtensionProviders } = await import("./discover.js");
|
|
35
|
+
try {
|
|
36
|
+
for (const d of await discoverExtensionProviders()) {
|
|
37
|
+
const existing = byId.get(d.id);
|
|
38
|
+
if (existing) {
|
|
39
|
+
if (d.noAuth && !existing.noAuth)
|
|
40
|
+
existing.noAuth = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const entry = { id: d.id, label: d.id, custom: true, noAuth: d.noAuth };
|
|
44
|
+
out.push(entry);
|
|
45
|
+
byId.set(d.id, entry);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
31
51
|
/** Resolve an id against known + settings entries only. Returns null for
|
|
32
52
|
* unattached or unknown ids — callers decide whether to accept them. */
|
|
33
53
|
export function findProvider(id) {
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
declare module "../core/event-bus.js" {
|
|
3
|
+
interface BusEvents {
|
|
4
|
+
/** Startup banner collection (sync pipe). Extensions contribute
|
|
5
|
+
* labeled item lists; the CLI renders them between the product
|
|
6
|
+
* name and the help hint. */
|
|
7
|
+
"banner:collect": {
|
|
8
|
+
sections: Array<{
|
|
9
|
+
label: string;
|
|
10
|
+
items: string[];
|
|
11
|
+
}>;
|
|
12
|
+
/** Name of the backend being launched. Extensions should gate
|
|
13
|
+
* per-backend sections on this rather than settings.defaultBackend. */
|
|
14
|
+
activeBackend?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
2
18
|
export {};
|
package/dist/cli/index.js
CHANGED
|
@@ -60,9 +60,18 @@ async function main() {
|
|
|
60
60
|
// ── Core (frontend-agnostic) ──────────────────────────────────
|
|
61
61
|
const core = createCore(config);
|
|
62
62
|
const { bus } = core;
|
|
63
|
-
// Track agent info from bus events (populated by extension backends)
|
|
64
63
|
let agentInfo = null;
|
|
65
|
-
bus.on("agent:info", (info) => {
|
|
64
|
+
bus.on("agent:info", (info) => {
|
|
65
|
+
agentInfo = info;
|
|
66
|
+
// Redraw so late agent:info emits (opencode-bridge after session.create) reach the prompt.
|
|
67
|
+
bus.emit("config:changed", {});
|
|
68
|
+
});
|
|
69
|
+
// tui-renderer subscribes to ui:error inside activateShell, after backend
|
|
70
|
+
// activation — pipe to stderr until the shell is up so boot failures surface.
|
|
71
|
+
const bootUiError = (e) => {
|
|
72
|
+
process.stderr.write(`agent-sh: ${e.message}\n`);
|
|
73
|
+
};
|
|
74
|
+
bus.on("ui:error", bootUiError);
|
|
66
75
|
// ── Interactive frontend ──────────────────────────────────────
|
|
67
76
|
if (process.env.DEBUG) {
|
|
68
77
|
console.error('[agent-sh] Setting up interactive frontend...');
|
|
@@ -157,6 +166,7 @@ async function main() {
|
|
|
157
166
|
return { info: "" };
|
|
158
167
|
},
|
|
159
168
|
});
|
|
169
|
+
bus.off("ui:error", bootUiError);
|
|
160
170
|
bus.emit("input-mode:register", {
|
|
161
171
|
id: "agent",
|
|
162
172
|
trigger: ">",
|
package/dist/cli/install.d.ts
CHANGED
package/dist/cli/install.js
CHANGED
|
@@ -75,6 +75,84 @@ function readPackageJson(target) {
|
|
|
75
75
|
return null;
|
|
76
76
|
return JSON.parse(fs.readFileSync(pkgJson, "utf-8"));
|
|
77
77
|
}
|
|
78
|
+
function hostAgentShVersion() {
|
|
79
|
+
try {
|
|
80
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf-8"));
|
|
81
|
+
return typeof pkg.version === "string" ? pkg.version : null;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function satisfies(version, spec) {
|
|
88
|
+
if (spec === version || spec === "*" || spec === "latest")
|
|
89
|
+
return true;
|
|
90
|
+
const [vMaj, vMin, vPatch] = version.split(/[.-]/, 3).map(Number);
|
|
91
|
+
if ([vMaj, vMin, vPatch].some(Number.isNaN))
|
|
92
|
+
return true;
|
|
93
|
+
const m = spec.match(/^([\^~]?)(\d+)\.(\d+)\.(\d+)/);
|
|
94
|
+
if (!m)
|
|
95
|
+
return true;
|
|
96
|
+
const op = m[1];
|
|
97
|
+
const sMaj = Number(m[2]);
|
|
98
|
+
const sMin = Number(m[3]);
|
|
99
|
+
const sPatch = Number(m[4]);
|
|
100
|
+
if (op === "")
|
|
101
|
+
return vMaj === sMaj && vMin === sMin && vPatch === sPatch;
|
|
102
|
+
if (op === "~")
|
|
103
|
+
return vMaj === sMaj && vMin === sMin && vPatch >= sPatch;
|
|
104
|
+
// ^x.y.z: zero-major treats minor as the breaking boundary (npm rule).
|
|
105
|
+
if (sMaj > 0)
|
|
106
|
+
return vMaj === sMaj && (vMin > sMin || (vMin === sMin && vPatch >= sPatch));
|
|
107
|
+
if (sMin > 0)
|
|
108
|
+
return vMaj === 0 && vMin === sMin && vPatch >= sPatch;
|
|
109
|
+
return vMaj === 0 && vMin === 0 && vPatch === sPatch;
|
|
110
|
+
}
|
|
111
|
+
/** Warn when the extension's `agent-sh` pin can't admit the host version;
|
|
112
|
+
* only rewrite when --sync-deps is set. */
|
|
113
|
+
function syncAgentShVersion(target, syncDeps) {
|
|
114
|
+
const hostVersion = hostAgentShVersion();
|
|
115
|
+
if (!hostVersion)
|
|
116
|
+
return;
|
|
117
|
+
// Prerelease hosts aren't on npm; rewriting would leave npm install unable to resolve.
|
|
118
|
+
if (hostVersion.includes("-"))
|
|
119
|
+
return;
|
|
120
|
+
const pkgJson = path.join(target, "package.json");
|
|
121
|
+
if (!fs.existsSync(pkgJson))
|
|
122
|
+
return;
|
|
123
|
+
const raw = fs.readFileSync(pkgJson, "utf-8");
|
|
124
|
+
const pkg = JSON.parse(raw);
|
|
125
|
+
const sections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
126
|
+
const name = path.basename(target);
|
|
127
|
+
let changed = false;
|
|
128
|
+
let warned = false;
|
|
129
|
+
for (const section of sections) {
|
|
130
|
+
const deps = pkg[section];
|
|
131
|
+
if (!deps || typeof deps !== "object")
|
|
132
|
+
continue;
|
|
133
|
+
const d = deps;
|
|
134
|
+
const current = d["agent-sh"];
|
|
135
|
+
if (typeof current !== "string")
|
|
136
|
+
continue;
|
|
137
|
+
if (current.startsWith("file:"))
|
|
138
|
+
continue;
|
|
139
|
+
if (satisfies(hostVersion, current))
|
|
140
|
+
continue;
|
|
141
|
+
if (syncDeps) {
|
|
142
|
+
console.log(`agent-sh: rewriting ${name} agent-sh ${current} -> ${hostVersion}.`);
|
|
143
|
+
d["agent-sh"] = hostVersion;
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
else if (!warned) {
|
|
147
|
+
console.warn(`agent-sh: ${name} pins agent-sh ${current}, which doesn't admit host ${hostVersion}. ` +
|
|
148
|
+
`npm install will land an older agent-sh inside the extension and drift from the running host. ` +
|
|
149
|
+
`Re-run with --sync-deps to rewrite the pin to ${hostVersion}, or update the bridge's source pin.`);
|
|
150
|
+
warned = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (changed)
|
|
154
|
+
fs.writeFileSync(pkgJson, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
155
|
+
}
|
|
78
156
|
/** Relative `file:` deps in bundled extensions (e.g. `"agent-sh": "file:../../.."`)
|
|
79
157
|
* point at the wrong location after the source is copied into ~/.agent-sh/extensions/.
|
|
80
158
|
* Resolve them against the original source dir so npm install in the target succeeds. */
|
|
@@ -165,7 +243,7 @@ function linkBins(target, pkg) {
|
|
|
165
243
|
}
|
|
166
244
|
export async function runInstall(spec, opts = {}) {
|
|
167
245
|
if (!spec) {
|
|
168
|
-
console.error("Usage: agent-sh install <name|file:|npm:|github:> [--force]\n\n" +
|
|
246
|
+
console.error("Usage: agent-sh install <name|file:|npm:|github:> [--force] [--sync-deps]\n\n" +
|
|
169
247
|
"Bundled extensions:\n" +
|
|
170
248
|
listBundled()
|
|
171
249
|
.map((n) => ` ${n}`)
|
|
@@ -191,9 +269,15 @@ export async function runInstall(spec, opts = {}) {
|
|
|
191
269
|
}
|
|
192
270
|
let linkedBins = [];
|
|
193
271
|
if (resolved.isDirectory) {
|
|
194
|
-
fs.cpSync(resolved.sourcePath, target, {
|
|
272
|
+
fs.cpSync(resolved.sourcePath, target, {
|
|
273
|
+
recursive: true,
|
|
274
|
+
// Skip source node_modules: maybeNpmInstall short-circuits on
|
|
275
|
+
// existing node_modules, silently leaving the bridge's deps stale.
|
|
276
|
+
filter: (src) => path.basename(src) !== "node_modules",
|
|
277
|
+
});
|
|
195
278
|
try {
|
|
196
279
|
rewriteFileDeps(target, resolved.sourcePath);
|
|
280
|
+
syncAgentShVersion(target, opts.syncDeps ?? false);
|
|
197
281
|
const pkg = readPackageJson(target);
|
|
198
282
|
if (pkg) {
|
|
199
283
|
maybeNpmInstall(target, pkg);
|
package/dist/cli/subcommands.js
CHANGED
|
@@ -3,7 +3,10 @@ import { runInstall, runUninstall, runList } from "./install.js";
|
|
|
3
3
|
import { runAuth } from "./auth/cli.js";
|
|
4
4
|
const SUBCOMMANDS = {
|
|
5
5
|
init: (args) => runInit({ force: args.includes("--force") }),
|
|
6
|
-
install: (args) => runInstall(args[0] ?? "", {
|
|
6
|
+
install: (args) => runInstall(args[0] ?? "", {
|
|
7
|
+
force: args.includes("--force"),
|
|
8
|
+
syncDeps: args.includes("--sync-deps"),
|
|
9
|
+
}),
|
|
7
10
|
uninstall: (args) => runUninstall(args[0] ?? ""),
|
|
8
11
|
list: () => runList(),
|
|
9
12
|
auth: (args) => runAuth(args),
|