@gajae-code/coding-agent 0.16.7 → 0.17.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/CHANGELOG.md +180 -1
- package/dist/types/capability/fs.d.ts +37 -4
- package/dist/types/capability/index.d.ts +19 -0
- package/dist/types/capability/types.d.ts +9 -0
- package/dist/types/cli/doctor/args.d.ts +36 -0
- package/dist/types/cli/doctor/checks.d.ts +18 -0
- package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
- package/dist/types/cli/doctor/context.d.ts +89 -0
- package/dist/types/cli/doctor/files.d.ts +27 -0
- package/dist/types/cli/doctor/ids.d.ts +20 -0
- package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
- package/dist/types/cli/doctor/journal.d.ts +43 -0
- package/dist/types/cli/doctor/managed-link.d.ts +39 -0
- package/dist/types/cli/doctor/native-probe.d.ts +2 -0
- package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
- package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
- package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
- package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
- package/dist/types/cli/doctor/probe-client.d.ts +9 -0
- package/dist/types/cli/doctor/probe-types.d.ts +18 -0
- package/dist/types/cli/doctor/probe.d.ts +3 -0
- package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
- package/dist/types/cli/doctor/repairs.d.ts +28 -0
- package/dist/types/cli/doctor/report.d.ts +27 -0
- package/dist/types/cli/doctor/runner.d.ts +4 -0
- package/dist/types/cli/doctor/safety.d.ts +10 -0
- package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
- package/dist/types/cli/doctor/service-targets.d.ts +41 -0
- package/dist/types/cli/doctor/types.d.ts +145 -0
- package/dist/types/cli/doctor-cli.d.ts +7 -0
- package/dist/types/cli/doctor-supervisor.d.ts +121 -0
- package/dist/types/cli/doctor-worker.d.ts +29 -0
- package/dist/types/cli/install-activation.d.ts +158 -0
- package/dist/types/cli/macos-community-app.d.ts +41 -0
- package/dist/types/cli/mcp-cli.d.ts +0 -11
- package/dist/types/cli/update-cli.d.ts +41 -4
- package/dist/types/cli-main.d.ts +174 -0
- package/dist/types/cli.d.ts +1 -171
- package/dist/types/commands/doctor.d.ts +7 -0
- package/dist/types/commands/sdk.d.ts +17 -8
- package/dist/types/config/autorouting-tier-map.d.ts +19 -0
- package/dist/types/config/file-lock.d.ts +27 -3
- package/dist/types/config/model-preset-registry.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +12 -5
- package/dist/types/config/model-resolver.d.ts +16 -3
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
- package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
- package/dist/types/cursor.d.ts +9 -9
- package/dist/types/discovery/agents-md.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +36 -7
- package/dist/types/discovery/index.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +22 -1
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/plugins/manager.d.ts +33 -4
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
- package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
- package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
- package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
- package/dist/types/main.d.ts +19 -1
- package/dist/types/modes/acp/acp-agent.d.ts +40 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
- package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -2
- package/dist/types/sdk/acp/adapter.d.ts +5 -1
- package/dist/types/sdk/broker/broker.d.ts +51 -0
- package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
- package/dist/types/sdk/broker/discovery.d.ts +38 -0
- package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
- package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
- package/dist/types/sdk/broker/runtime.d.ts +26 -0
- package/dist/types/sdk/broker/session-index.d.ts +13 -4
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
- package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
- package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
- package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
- package/dist/types/sdk/bus/index.d.ts +2 -0
- package/dist/types/sdk/bus/notification-service.d.ts +3 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
- package/dist/types/sdk/cli/session-cli.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +4 -0
- package/dist/types/sdk/host/surface-policy.d.ts +3 -1
- package/dist/types/sdk/lifecycle/service.d.ts +44 -10
- package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
- package/dist/types/sdk/prompt-failure.d.ts +47 -0
- package/dist/types/sdk/prompt-status.d.ts +19 -0
- package/dist/types/sdk/router/session-router.d.ts +3 -4
- package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
- package/dist/types/sdk/session-authority.d.ts +9 -0
- package/dist/types/sdk/session.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +1 -1
- package/dist/types/session/fallback-chain-controller.d.ts +3 -6
- package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
- package/dist/types/session/primary-control-surface.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +6 -0
- package/dist/types/tools/ask.d.ts +25 -0
- package/dist/types/tools/image-gen.d.ts +0 -4
- package/dist/types/tools/skill-discovery.d.ts +7 -5
- package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
- package/dist/types/utils/changelog.d.ts +0 -9
- package/dist/types/utils/mupdf-wasm.d.ts +1 -0
- package/package.json +9 -8
- package/scripts/compile-args.ts +8 -4
- package/src/capability/fs.ts +395 -17
- package/src/capability/index.ts +273 -10
- package/src/capability/types.ts +9 -0
- package/src/cli/customize-doctor.ts +18 -12
- package/src/cli/doctor/args.ts +236 -0
- package/src/cli/doctor/checks.ts +431 -0
- package/src/cli/doctor/config-repairs.ts +517 -0
- package/src/cli/doctor/context.ts +149 -0
- package/src/cli/doctor/files.ts +149 -0
- package/src/cli/doctor/ids.ts +115 -0
- package/src/cli/doctor/install-repairs.ts +335 -0
- package/src/cli/doctor/journal.ts +423 -0
- package/src/cli/doctor/managed-link.ts +514 -0
- package/src/cli/doctor/native-probe.ts +13 -0
- package/src/cli/doctor/permission-repairs.ts +242 -0
- package/src/cli/doctor/plugin-quarantine.ts +377 -0
- package/src/cli/doctor/plugin-restore.ts +59 -0
- package/src/cli/doctor/plugin-targets.ts +373 -0
- package/src/cli/doctor/probe-client.ts +195 -0
- package/src/cli/doctor/probe-types.ts +21 -0
- package/src/cli/doctor/probe.ts +42 -0
- package/src/cli/doctor/projection-probe.ts +249 -0
- package/src/cli/doctor/repairs.ts +1157 -0
- package/src/cli/doctor/report.ts +176 -0
- package/src/cli/doctor/runner.ts +342 -0
- package/src/cli/doctor/safety.ts +40 -0
- package/src/cli/doctor/service-repairs.ts +452 -0
- package/src/cli/doctor/service-targets.ts +274 -0
- package/src/cli/doctor/types.ts +164 -0
- package/src/cli/doctor-cli.ts +62 -0
- package/src/cli/doctor-supervisor.ts +571 -0
- package/src/cli/doctor-worker.ts +181 -0
- package/src/cli/install-activation.ts +666 -0
- package/src/cli/macos-community-app.ts +1449 -0
- package/src/cli/mcp-cli.ts +11 -21
- package/src/cli/nofile-limit.ts +5 -1
- package/src/cli/plugin-cli.ts +6 -1
- package/src/cli/update-cli.ts +362 -264
- package/src/cli-main.ts +517 -0
- package/src/cli.ts +64 -433
- package/src/commands/autoresearch.ts +11 -5
- package/src/commands/completion.ts +1 -1
- package/src/commands/doctor.ts +13 -0
- package/src/commands/sdk.ts +58 -10
- package/src/commands/ultragoal.ts +11 -5
- package/src/config/autorouting-tier-map.ts +7 -0
- package/src/config/file-lock.ts +736 -71
- package/src/config/mcp-schema.json +3 -3
- package/src/config/model-preset-registry.ts +1 -0
- package/src/config/model-registry.ts +80 -27
- package/src/config/model-resolver.ts +33 -4
- package/src/config/models-config-schema.ts +2 -0
- package/src/config/settings-schema.ts +6 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -0
- package/src/coordinator-mcp/server.ts +534 -51
- package/src/coordinator-mcp/session-reaper.ts +64 -8
- package/src/cursor.ts +223 -53
- package/src/discovery/agents-md.ts +74 -8
- package/src/discovery/agents.ts +32 -7
- package/src/discovery/builtin.ts +184 -75
- package/src/discovery/claude-plugins.ts +85 -17
- package/src/discovery/cline.ts +38 -10
- package/src/discovery/cursor.ts +19 -6
- package/src/discovery/gemini.ts +62 -22
- package/src/discovery/github.ts +13 -3
- package/src/discovery/helpers.ts +483 -89
- package/src/discovery/index.ts +1 -0
- package/src/discovery/mcp-json.ts +36 -10
- package/src/discovery/opencode.ts +36 -19
- package/src/discovery/ssh.ts +11 -8
- package/src/discovery/windsurf.ts +12 -3
- package/src/exec/bash-executor.ts +10 -3
- package/src/exec/isolated-shell.ts +15 -2
- package/src/extensibility/extensions/loader.ts +88 -26
- package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
- package/src/extensibility/gjc-plugins/paths.ts +4 -1
- package/src/extensibility/gjc-plugins/types.ts +27 -0
- package/src/extensibility/plugins/manager.ts +200 -22
- package/src/extensibility/plugins/marketplace/cache.ts +55 -2
- package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
- package/src/extensibility/plugins/marketplace/registry.ts +153 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
- package/src/extensibility/runtime-skill-discovery.ts +61 -9
- package/src/extensibility/skill-management.ts +7 -1
- package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
- package/src/gjc-runtime/launch-worktree.test.ts +248 -0
- package/src/gjc-runtime/launch-worktree.ts +275 -38
- package/src/gjc-runtime/repository-binding.ts +26 -1
- package/src/gjc-runtime/session-layout.ts +10 -0
- package/src/gjc-runtime/session-state-lock.ts +330 -23
- package/src/gjc-runtime/session-state-sidecar.ts +328 -80
- package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +28 -26
- package/src/main.ts +150 -29
- package/src/memories/index.ts +24 -2
- package/src/modes/acp/acp-agent.ts +522 -68
- package/src/modes/components/agent-dashboard.ts +3 -1
- package/src/modes/components/model-selector.ts +28 -19
- package/src/modes/components/plugin-settings.ts +2 -1
- package/src/modes/controllers/selector-controller.ts +15 -9
- package/src/modes/interactive-mode.ts +21 -3
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/move-session.md +4 -0
- package/src/prompts/tools/read.md +2 -1
- package/src/prompts/tools/skill-discovery.md +6 -5
- package/src/prompts/tools/task.md +1 -0
- package/src/runtime-mcp/config-writer.ts +228 -0
- package/src/runtime-mcp/oauth-discovery.ts +114 -14
- package/src/runtime-mcp/policy-json-edit.ts +129 -0
- package/src/runtime-mcp/startup-policy.ts +14 -0
- package/src/runtime-mcp/types.ts +2 -2
- package/src/sdk/acp/adapter.ts +27 -12
- package/src/sdk/broker/broker.ts +273 -44
- package/src/sdk/broker/daemon-entry.ts +119 -0
- package/src/sdk/broker/discovery.ts +173 -20
- package/src/sdk/broker/doctor-restart.ts +206 -0
- package/src/sdk/broker/endpoint-authority.ts +36 -0
- package/src/sdk/broker/ensure.ts +49 -14
- package/src/sdk/broker/lifecycle.ts +174 -42
- package/src/sdk/broker/process-incarnation.ts +86 -2
- package/src/sdk/broker/runtime.ts +145 -21
- package/src/sdk/broker/session-index.ts +136 -22
- package/src/sdk/broker/spawn-substrate.ts +4 -1
- package/src/sdk/broker/transport.ts +5 -0
- package/src/sdk/broker/worktree-occupancy.ts +21 -1
- package/src/sdk/bus/chat-daemon-cli.ts +63 -0
- package/src/sdk/bus/chat-daemon-control.ts +260 -64
- package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
- package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
- package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
- package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
- package/src/sdk/bus/index.ts +252 -51
- package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
- package/src/sdk/bus/notification-service.ts +21 -3
- package/src/sdk/bus/reconciliation-store.ts +17 -11
- package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/bus/telegram-daemon-control.ts +47 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
- package/src/sdk/bus/telegram-daemon.ts +178 -13
- package/src/sdk/cli/session-cli.ts +100 -12
- package/src/sdk/host/host.ts +2 -7
- package/src/sdk/host/session-runtime.test.ts +329 -8
- package/src/sdk/host/session-runtime.ts +202 -50
- package/src/sdk/host/surface-policy.ts +8 -1
- package/src/sdk/lifecycle/service.ts +199 -22
- package/src/sdk/mcp/server.ts +1 -1
- package/src/sdk/prompt-deadline-lease.ts +12 -4
- package/src/sdk/prompt-deadline-manager.ts +5 -7
- package/src/sdk/prompt-failure.ts +148 -0
- package/src/sdk/prompt-status.ts +30 -1
- package/src/sdk/prompt-watchdog.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +18 -0
- package/src/sdk/protocol/operation-registry.ts +20 -8
- package/src/sdk/router/session-router.ts +8 -3
- package/src/sdk/service-artifact-paths.ts +26 -0
- package/src/sdk/session-authority.ts +10 -0
- package/src/sdk/session.ts +361 -194
- package/src/session/agent-session.ts +398 -93
- package/src/session/blob-store.ts +9 -9
- package/src/session/fallback-chain-controller.ts +3 -7
- package/src/session/internal/managed-session-scope.ts +445 -29
- package/src/session/internal/managed-session-storage.ts +38 -6
- package/src/session/primary-control-surface.ts +12 -0
- package/src/session/session-manager.ts +11 -3
- package/src/session/session-storage.ts +1 -1
- package/src/session-import/codex.ts +6 -1
- package/src/session-import/redact.ts +7 -0
- package/src/skill-state/workflow-mutation-guard.ts +645 -39
- package/src/slash-commands/builtin-registry.ts +7 -3
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +36 -3
- package/src/task/types.ts +27 -5
- package/src/tools/ask.ts +114 -34
- package/src/tools/browser/actions.ts +2 -2
- package/src/tools/browser/tab-worker.ts +11 -8
- package/src/tools/descriptors.ts +6 -1
- package/src/tools/fetch.ts +7 -2
- package/src/tools/image-gen.ts +33 -34
- package/src/tools/read.ts +78 -32
- package/src/tools/skill-discovery.ts +17 -7
- package/src/tools/tool-catalog.generated.ts +8 -8
- package/src/tools/ultragoal-ask-guard.ts +16 -26
- package/src/utils/changelog.ts +7 -1
- package/src/utils/git.ts +3 -1
- package/src/utils/markit.ts +24 -2
- package/src/utils/mupdf-wasm.ts +26 -0
- package/src/web/search/providers/openai-compatible.ts +191 -14
package/src/discovery/index.ts
CHANGED
|
@@ -11,10 +11,10 @@ import * as fsPromises from "node:fs/promises";
|
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { logger, tryParseJson } from "@gajae-code/utils";
|
|
13
13
|
import { registerProvider } from "../capability";
|
|
14
|
-
import { readFile } from "../capability/fs";
|
|
14
|
+
import { type ReadFileOptions, readFile } from "../capability/fs";
|
|
15
15
|
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
16
16
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
17
|
-
import { createSourceMeta, expandEnvVarsDeep } from "./helpers";
|
|
17
|
+
import { canonicalizePathWithinHome, createSourceMeta, expandEnvVarsDeep, getReadOptions } from "./helpers";
|
|
18
18
|
|
|
19
19
|
const PROVIDER_ID = "mcp-json";
|
|
20
20
|
const DISPLAY_NAME = "MCP Config";
|
|
@@ -440,18 +440,40 @@ async function readExactMCPConfigFile(filePath: string): Promise<string | null>
|
|
|
440
440
|
export async function loadMCPJsonFile(
|
|
441
441
|
filePath: string,
|
|
442
442
|
level: "user" | "project",
|
|
443
|
-
options?: { quiet?: boolean; useCache?: boolean },
|
|
443
|
+
options?: { quiet?: boolean; useCache?: boolean; readOptions?: ReadFileOptions },
|
|
444
444
|
): Promise<MCPJsonLoadResult> {
|
|
445
445
|
const warnings: string[] = [];
|
|
446
446
|
const items: MCPServer[] = [];
|
|
447
|
+
let sourcePath = filePath;
|
|
448
|
+
if (options?.readOptions?.isolatedHome) {
|
|
449
|
+
if (typeof options.readOptions.home !== "string") {
|
|
450
|
+
if (options.quiet) warnings.push("MCP configuration unavailable");
|
|
451
|
+
return { items, warnings, disabledServers: [] };
|
|
452
|
+
}
|
|
453
|
+
const authorizedPath = await canonicalizePathWithinHome(
|
|
454
|
+
{
|
|
455
|
+
home: options.readOptions.home,
|
|
456
|
+
isolatedHome: true,
|
|
457
|
+
userAgentDir: options.readOptions.userAgentDir,
|
|
458
|
+
},
|
|
459
|
+
filePath,
|
|
460
|
+
undefined,
|
|
461
|
+
options.readOptions.scope ?? "project",
|
|
462
|
+
);
|
|
463
|
+
if (!authorizedPath) {
|
|
464
|
+
if (options.quiet) warnings.push("MCP configuration unavailable");
|
|
465
|
+
return { items, warnings, disabledServers: [] };
|
|
466
|
+
}
|
|
467
|
+
sourcePath = authorizedPath;
|
|
468
|
+
}
|
|
447
469
|
|
|
448
470
|
const content = options?.quiet
|
|
449
|
-
?
|
|
471
|
+
? options.readOptions?.isolatedHome
|
|
472
|
+
? await readFile(sourcePath, { ...options.readOptions, bypassCache: true })
|
|
473
|
+
: await readExactMCPConfigFile(sourcePath)
|
|
450
474
|
: options?.useCache === false
|
|
451
|
-
? await
|
|
452
|
-
|
|
453
|
-
.catch(() => null)
|
|
454
|
-
: await readFile(filePath);
|
|
475
|
+
? await readFile(filePath, { ...options.readOptions, bypassCache: true })
|
|
476
|
+
: await readFile(filePath, options?.readOptions);
|
|
455
477
|
if (content === null) {
|
|
456
478
|
if (options?.quiet) warnings.push("MCP configuration unavailable");
|
|
457
479
|
return { items, warnings, disabledServers: [] };
|
|
@@ -474,7 +496,7 @@ export async function loadMCPJsonFile(
|
|
|
474
496
|
} else {
|
|
475
497
|
validConfig = config as MCPConfigFile;
|
|
476
498
|
}
|
|
477
|
-
const source = createSourceMeta(PROVIDER_ID,
|
|
499
|
+
const source = createSourceMeta(PROVIDER_ID, sourcePath, level);
|
|
478
500
|
items.push(...transformMCPConfig(validConfig, source, options?.quiet));
|
|
479
501
|
|
|
480
502
|
return {
|
|
@@ -490,7 +512,11 @@ export async function loadMCPJsonFile(
|
|
|
490
512
|
async function load(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
491
513
|
const filenames = ["mcp.json", ".mcp.json"];
|
|
492
514
|
const results = await Promise.all(
|
|
493
|
-
filenames.map(filename =>
|
|
515
|
+
filenames.map(filename =>
|
|
516
|
+
loadMCPJsonFile(path.join(ctx.cwd, filename), "project", {
|
|
517
|
+
readOptions: getReadOptions(ctx, "project"),
|
|
518
|
+
}),
|
|
519
|
+
),
|
|
494
520
|
);
|
|
495
521
|
|
|
496
522
|
const allItems = results.flatMap(r => r.items);
|
|
@@ -32,9 +32,11 @@ import type { Settings as RuntimeSettings } from "../config/settings";
|
|
|
32
32
|
|
|
33
33
|
import {
|
|
34
34
|
buildExtensionModuleItems,
|
|
35
|
+
canonicalizePathWithinHome,
|
|
35
36
|
createSourceMeta,
|
|
36
37
|
discoverExtensionModulePaths,
|
|
37
38
|
getProjectPath,
|
|
39
|
+
getReadOptions,
|
|
38
40
|
getUserPath,
|
|
39
41
|
loadFilesFromDir,
|
|
40
42
|
scanSkillsFromDir,
|
|
@@ -53,9 +55,12 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
|
|
|
53
55
|
const warnings: string[] = [];
|
|
54
56
|
|
|
55
57
|
// User-level only: ~/.config/opencode/AGENTS.md
|
|
56
|
-
const
|
|
58
|
+
const rawUserAgentsMd = getUserPath(ctx, "opencode", "AGENTS.md");
|
|
59
|
+
const userAgentsMd = rawUserAgentsMd
|
|
60
|
+
? await canonicalizePathWithinHome(ctx, rawUserAgentsMd, undefined, "user")
|
|
61
|
+
: null;
|
|
57
62
|
if (userAgentsMd) {
|
|
58
|
-
const content = await readFile(userAgentsMd);
|
|
63
|
+
const content = await readFile(userAgentsMd, getReadOptions(ctx, "user"));
|
|
59
64
|
if (content) {
|
|
60
65
|
items.push({
|
|
61
66
|
path: userAgentsMd,
|
|
@@ -115,8 +120,10 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
115
120
|
const projectPluginsDir = getProjectPath(ctx, "opencode", "plugins");
|
|
116
121
|
|
|
117
122
|
const [userPaths, projectPaths] = await Promise.all([
|
|
118
|
-
userPluginsDir ? discoverExtensionModulePaths(ctx, userPluginsDir) : Promise.resolve([]),
|
|
119
|
-
projectPluginsDir
|
|
123
|
+
userPluginsDir ? discoverExtensionModulePaths(ctx, userPluginsDir, { scope: "user" }) : Promise.resolve([]),
|
|
124
|
+
projectPluginsDir
|
|
125
|
+
? discoverExtensionModulePaths(ctx, projectPluginsDir, { scope: "project" })
|
|
126
|
+
: Promise.resolve([]),
|
|
120
127
|
]);
|
|
121
128
|
|
|
122
129
|
const items = buildExtensionModuleItems(PROVIDER_ID, userPaths, projectPaths);
|
|
@@ -201,9 +208,12 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<SettingsCapabi
|
|
|
201
208
|
const warnings: string[] = [];
|
|
202
209
|
|
|
203
210
|
// User-level: ~/.config/opencode/opencode.json
|
|
204
|
-
const
|
|
211
|
+
const rawUserConfigPath = getUserPath(ctx, "opencode", "opencode.json");
|
|
212
|
+
const userConfigPath = rawUserConfigPath
|
|
213
|
+
? await canonicalizePathWithinHome(ctx, rawUserConfigPath, undefined, "user")
|
|
214
|
+
: null;
|
|
205
215
|
if (userConfigPath) {
|
|
206
|
-
const content = await readFile(userConfigPath);
|
|
216
|
+
const content = await readFile(userConfigPath, getReadOptions(ctx, "user"));
|
|
207
217
|
if (content) {
|
|
208
218
|
const parsed = tryParseJson<Record<string, unknown>>(content);
|
|
209
219
|
if (parsed) {
|
|
@@ -220,19 +230,26 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<SettingsCapabi
|
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
// Project-level: opencode.json in project root
|
|
223
|
-
const projectConfigPath =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
const projectConfigPath = await canonicalizePathWithinHome(
|
|
234
|
+
ctx,
|
|
235
|
+
path.join(ctx.cwd, "opencode.json"),
|
|
236
|
+
undefined,
|
|
237
|
+
"project",
|
|
238
|
+
);
|
|
239
|
+
if (projectConfigPath) {
|
|
240
|
+
const content = await readFile(projectConfigPath, getReadOptions(ctx, "project"));
|
|
241
|
+
if (content) {
|
|
242
|
+
const parsed = tryParseJson<Record<string, unknown>>(content);
|
|
243
|
+
if (parsed) {
|
|
244
|
+
items.push({
|
|
245
|
+
path: projectConfigPath,
|
|
246
|
+
data: parsed,
|
|
247
|
+
level: "project",
|
|
248
|
+
_source: createSourceMeta(PROVIDER_ID, projectConfigPath, "project"),
|
|
249
|
+
});
|
|
250
|
+
} else {
|
|
251
|
+
warnings.push(`Invalid JSON in ${projectConfigPath}`);
|
|
252
|
+
}
|
|
236
253
|
}
|
|
237
254
|
}
|
|
238
255
|
|
package/src/discovery/ssh.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { type SSHHost, sshCapability } from "../capability/ssh";
|
|
|
12
12
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
13
13
|
import { validateSshDestination } from "../ssh/utils";
|
|
14
14
|
import { expandTilde } from "../tools/path-utils";
|
|
15
|
-
import { createSourceMeta, expandEnvVarsDeep } from "./helpers";
|
|
15
|
+
import { canonicalizePathWithinHome, createSourceMeta, expandEnvVarsDeep, getReadOptions } from "./helpers";
|
|
16
16
|
|
|
17
17
|
const PROVIDER_ID = "ssh-json";
|
|
18
18
|
const DISPLAY_NAME = "SSH Config";
|
|
@@ -102,29 +102,32 @@ async function loadSshJsonFile(
|
|
|
102
102
|
): Promise<LoadResult<SSHHost>> {
|
|
103
103
|
const items: SSHHost[] = [];
|
|
104
104
|
const warnings: string[] = [];
|
|
105
|
-
const
|
|
105
|
+
const scope = level === "user" ? "native" : "project";
|
|
106
|
+
const canonicalPath = await canonicalizePathWithinHome(ctx, filePath, undefined, scope);
|
|
107
|
+
if (!canonicalPath) return { items, warnings };
|
|
108
|
+
const content = await readFile(canonicalPath, getReadOptions(ctx, scope));
|
|
106
109
|
if (content === null) {
|
|
107
110
|
return { items, warnings };
|
|
108
111
|
}
|
|
109
112
|
const parsed = tryParseJson<SSHConfigFile>(content);
|
|
110
113
|
if (!parsed) {
|
|
111
|
-
warnings.push(`Failed to parse JSON in ${
|
|
114
|
+
warnings.push(`Failed to parse JSON in ${canonicalPath}`);
|
|
112
115
|
return { items, warnings };
|
|
113
116
|
}
|
|
114
117
|
const config = expandEnvVarsDeep(parsed);
|
|
115
118
|
if (!config.hosts || typeof config.hosts !== "object") {
|
|
116
|
-
warnings.push(`Missing hosts in ${
|
|
119
|
+
warnings.push(`Missing hosts in ${canonicalPath}`);
|
|
117
120
|
return { items, warnings };
|
|
118
121
|
}
|
|
119
122
|
|
|
120
|
-
const source = createSourceMeta(PROVIDER_ID,
|
|
123
|
+
const source = createSourceMeta(PROVIDER_ID, canonicalPath, level);
|
|
121
124
|
for (const [name, rawHost] of Object.entries(config.hosts)) {
|
|
122
125
|
if (!name.trim()) {
|
|
123
|
-
warnings.push(`Invalid SSH host name in ${
|
|
126
|
+
warnings.push(`Invalid SSH host name in ${canonicalPath}`);
|
|
124
127
|
continue;
|
|
125
128
|
}
|
|
126
129
|
if (!rawHost || typeof rawHost !== "object") {
|
|
127
|
-
warnings.push(`Invalid host entry in ${
|
|
130
|
+
warnings.push(`Invalid host entry in ${canonicalPath}: ${name}`);
|
|
128
131
|
continue;
|
|
129
132
|
}
|
|
130
133
|
const host = normalizeHost(name, rawHost, source, ctx.home, warnings);
|
|
@@ -139,7 +142,7 @@ async function loadSshJsonFile(
|
|
|
139
142
|
async function load(ctx: LoadContext): Promise<LoadResult<SSHHost>> {
|
|
140
143
|
const candidateSources: Array<{ path: string; level: "user" | "project" }> = [
|
|
141
144
|
{ path: getSSHConfigPath("project", ctx.cwd), level: "project" },
|
|
142
|
-
{ path: getSSHConfigPath("user", ctx.cwd), level: "user" },
|
|
145
|
+
{ path: getSSHConfigPath("user", ctx.cwd, ctx.userAgentDir), level: "user" },
|
|
143
146
|
{ path: path.join(ctx.cwd, "ssh.json"), level: "project" },
|
|
144
147
|
{ path: path.join(ctx.cwd, ".ssh.json"), level: "project" },
|
|
145
148
|
];
|
|
@@ -17,7 +17,15 @@ import { registerProvider } from "../capability";
|
|
|
17
17
|
import { readFile } from "../capability/fs";
|
|
18
18
|
import { type Rule, ruleCapability } from "../capability/rule";
|
|
19
19
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
buildRuleFromMarkdown,
|
|
22
|
+
canonicalizePathWithinHome,
|
|
23
|
+
createSourceMeta,
|
|
24
|
+
getProjectPath,
|
|
25
|
+
getReadOptions,
|
|
26
|
+
getUserPath,
|
|
27
|
+
loadFilesFromDir,
|
|
28
|
+
} from "./helpers";
|
|
21
29
|
|
|
22
30
|
const PROVIDER_ID = "windsurf";
|
|
23
31
|
const DISPLAY_NAME = "Windsurf";
|
|
@@ -32,9 +40,10 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
32
40
|
const warnings: string[] = [];
|
|
33
41
|
|
|
34
42
|
// User-level: ~/.codeium/windsurf/memories/global_rules.md
|
|
35
|
-
const
|
|
43
|
+
const rawUserPath = getUserPath(ctx, "windsurf", "memories/global_rules.md");
|
|
44
|
+
const userPath = rawUserPath ? await canonicalizePathWithinHome(ctx, rawUserPath, undefined, "user") : null;
|
|
36
45
|
if (userPath) {
|
|
37
|
-
const content = await readFile(userPath);
|
|
46
|
+
const content = await readFile(userPath, getReadOptions(ctx, "user"));
|
|
38
47
|
if (content) {
|
|
39
48
|
const source = createSourceMeta(PROVIDER_ID, userPath, "user");
|
|
40
49
|
items.push(buildRuleFromMarkdown("global_rules.md", content, userPath, source, { ruleName: "global_rules" }));
|
|
@@ -533,6 +533,10 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
533
533
|
!abortPromise
|
|
534
534
|
) {
|
|
535
535
|
abortPromise = activeShell.abort();
|
|
536
|
+
// Cancellation owns this acknowledgement immediately: the run can settle
|
|
537
|
+
// before cleanup reaches it, and worker close can reject both promises.
|
|
538
|
+
// Keep the original promise for cleanup without an unobserved window.
|
|
539
|
+
void abortPromise.catch(() => undefined);
|
|
536
540
|
}
|
|
537
541
|
};
|
|
538
542
|
const abortDeferred = Promise.withResolvers<"abort">();
|
|
@@ -549,9 +553,6 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
549
553
|
),
|
|
550
554
|
Bun.sleep(CANCEL_CLEANUP_WAIT_MS).then(() => false),
|
|
551
555
|
]);
|
|
552
|
-
if (abortPromise) {
|
|
553
|
-
await Promise.race([abortPromise.catch(() => undefined), Bun.sleep(CANCEL_CLEANUP_WAIT_MS)]);
|
|
554
|
-
}
|
|
555
556
|
return settled;
|
|
556
557
|
};
|
|
557
558
|
if (userSignal) {
|
|
@@ -797,6 +798,12 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
797
798
|
const disposePromise = oneShotShell.close();
|
|
798
799
|
await Promise.race([disposePromise.catch(() => undefined), Bun.sleep(CANCEL_CLEANUP_WAIT_MS)]);
|
|
799
800
|
}
|
|
801
|
+
// Also join cancellation requested after run settlement or on a path that
|
|
802
|
+
// skipped run cleanup. Close first so a pending acknowledgement cannot
|
|
803
|
+
// hold a one-shot worker open.
|
|
804
|
+
if (abortPromise) {
|
|
805
|
+
await Promise.race([abortPromise.catch(() => undefined), Bun.sleep(CANCEL_CLEANUP_WAIT_MS)]);
|
|
806
|
+
}
|
|
800
807
|
}
|
|
801
808
|
}
|
|
802
809
|
|
|
@@ -153,8 +153,16 @@ export class IsolatedShell {
|
|
|
153
153
|
}
|
|
154
154
|
this.#pending.set(id, pending);
|
|
155
155
|
const { signal: _signal, ...workerOptions } = options;
|
|
156
|
+
try {
|
|
157
|
+
this.#send({ type: "run", token: this.#protocolToken, id, options: workerOptions });
|
|
158
|
+
} catch (error) {
|
|
159
|
+
// A failed send has no protocol response owner. Do not leave its
|
|
160
|
+
// unobserved deferred for close() to reject later.
|
|
161
|
+
this.#pending.delete(id);
|
|
162
|
+
pending.removeAbortListener?.();
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
156
165
|
if (options.signal instanceof AbortSignal) this.#dispatchedRunSignals.add(options.signal);
|
|
157
|
-
this.#send({ type: "run", token: this.#protocolToken, id, options: workerOptions });
|
|
158
166
|
return await deferred.promise;
|
|
159
167
|
} finally {
|
|
160
168
|
if (options.signal instanceof AbortSignal) this.#activeRunSignals.delete(options.signal);
|
|
@@ -193,7 +201,12 @@ export class IsolatedShell {
|
|
|
193
201
|
const id = this.#nextId++;
|
|
194
202
|
const deferred = Promise.withResolvers<void>();
|
|
195
203
|
this.#pending.set(id, { kind: "void", resolve: deferred.resolve, reject: deferred.reject });
|
|
196
|
-
|
|
204
|
+
try {
|
|
205
|
+
this.#send({ type, token: this.#protocolToken, id });
|
|
206
|
+
} catch (error) {
|
|
207
|
+
this.#pending.delete(id);
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
197
210
|
await deferred.promise;
|
|
198
211
|
}
|
|
199
212
|
|
|
@@ -7,9 +7,10 @@ import * as path from "node:path";
|
|
|
7
7
|
import type { ThinkingLevel } from "@gajae-code/agent-core";
|
|
8
8
|
import type { ImageContent, Model, TextContent, Tool, UsageReport } from "@gajae-code/ai/core";
|
|
9
9
|
import type { KeyId } from "@gajae-code/tui";
|
|
10
|
-
import { hasFsCode, isEacces, isEnoent, logger } from "@gajae-code/utils";
|
|
10
|
+
import { hasFsCode, isEacces, isEnoent, logger, safeErrorDescription } from "@gajae-code/utils";
|
|
11
11
|
import * as Zod from "zod/v4";
|
|
12
12
|
import { type ExtensionModule, extensionModuleCapability } from "../../capability/extension-module";
|
|
13
|
+
import type { Settings } from "../../config/settings";
|
|
13
14
|
import { loadCapability } from "../../discovery";
|
|
14
15
|
import { getExtensionNameFromPath } from "../../discovery/helpers";
|
|
15
16
|
import type { ExecOptions } from "../../exec/exec";
|
|
@@ -511,9 +512,9 @@ async function loadExtension(
|
|
|
511
512
|
eventBus: EventBus,
|
|
512
513
|
runtime: IExtensionRuntime,
|
|
513
514
|
): Promise<{ extension: Extension | null; error: string | null }> {
|
|
514
|
-
const resolvedPath = resolvePath(extensionPath, cwd);
|
|
515
515
|
let activation: ExtensionActivationScope | undefined;
|
|
516
516
|
try {
|
|
517
|
+
const resolvedPath = resolvePath(extensionPath, cwd);
|
|
517
518
|
const module = (await loadLegacyPiModule(resolvedPath)) as LoadedExtensionModule;
|
|
518
519
|
const factory = getExtensionFactory(module);
|
|
519
520
|
|
|
@@ -540,8 +541,7 @@ async function loadExtension(
|
|
|
540
541
|
return { extension, error: null };
|
|
541
542
|
} catch (err) {
|
|
542
543
|
activation?.rollback();
|
|
543
|
-
|
|
544
|
-
return { extension: null, error: `Failed to load extension: ${message}` };
|
|
544
|
+
return { extension: null, error: `Failed to load extension: ${safeErrorDescription(err)}` };
|
|
545
545
|
}
|
|
546
546
|
}
|
|
547
547
|
|
|
@@ -588,7 +588,7 @@ export async function loadExtensions(paths: string[], cwd: string, eventBus?: Ev
|
|
|
588
588
|
const { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);
|
|
589
589
|
|
|
590
590
|
if (error) {
|
|
591
|
-
errors.push({ path: extPath, error });
|
|
591
|
+
errors.push({ path: safeErrorDescription(extPath), error });
|
|
592
592
|
continue;
|
|
593
593
|
}
|
|
594
594
|
|
|
@@ -622,7 +622,7 @@ async function readExtensionManifest(packageJsonPath: string): Promise<Extension
|
|
|
622
622
|
if (isEnoent(error) || isEacces(error) || hasFsCode(error, "EPERM")) {
|
|
623
623
|
return null;
|
|
624
624
|
}
|
|
625
|
-
logger.warn("Failed to read extension manifest", { path: packageJsonPath, error:
|
|
625
|
+
logger.warn("Failed to read extension manifest", { path: packageJsonPath, error: safeErrorDescription(error) });
|
|
626
626
|
return null;
|
|
627
627
|
}
|
|
628
628
|
}
|
|
@@ -705,7 +705,7 @@ async function discoverExtensionsInDir(dir: string): Promise<string[]> {
|
|
|
705
705
|
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
706
706
|
} catch (err) {
|
|
707
707
|
if (isEnoent(err)) return [];
|
|
708
|
-
logger.warn("Failed to discover extensions in directory", { path: dir, error:
|
|
708
|
+
logger.warn("Failed to discover extensions in directory", { path: dir, error: safeErrorDescription(err) });
|
|
709
709
|
return [];
|
|
710
710
|
}
|
|
711
711
|
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
@@ -729,6 +729,27 @@ async function discoverExtensionsInDir(dir: string): Promise<string[]> {
|
|
|
729
729
|
return discovered;
|
|
730
730
|
}
|
|
731
731
|
|
|
732
|
+
/**
|
|
733
|
+
* Session-scoped discovery inputs.
|
|
734
|
+
*
|
|
735
|
+
* A session's selected agent directory is not necessarily the process-global
|
|
736
|
+
* one (`createAgentSession({ agentDir })`), so user-scope extension modules and
|
|
737
|
+
* provider policy must resolve against the caller's profile rather than
|
|
738
|
+
* `getAgentDir()`.
|
|
739
|
+
*/
|
|
740
|
+
export interface DiscoverExtensionsOptions {
|
|
741
|
+
/**
|
|
742
|
+
* Agent directory backing user-scope discovery. Default: `getAgentDir()`.
|
|
743
|
+
* Only the native capability provider is scoped this way; installed
|
|
744
|
+
* plugin-bundle extension paths stay home-scoped by design.
|
|
745
|
+
*/
|
|
746
|
+
agentDir?: string;
|
|
747
|
+
/** Resolver-owned classification for `agentDir`. */
|
|
748
|
+
profileAuthority?: "default" | "custom";
|
|
749
|
+
/** Session settings whose provider policy applies to this load. */
|
|
750
|
+
settings?: Settings;
|
|
751
|
+
}
|
|
752
|
+
|
|
732
753
|
/**
|
|
733
754
|
* Discover and load extensions from standard locations.
|
|
734
755
|
*/
|
|
@@ -737,14 +758,21 @@ export async function discoverAndLoadExtensions(
|
|
|
737
758
|
cwd: string,
|
|
738
759
|
eventBus?: EventBus,
|
|
739
760
|
disabledExtensionIds: string[] = [],
|
|
761
|
+
options: DiscoverExtensionsOptions = {},
|
|
740
762
|
): Promise<LoadExtensionsResult> {
|
|
741
763
|
const allPaths: string[] = [];
|
|
742
764
|
const seen = new Set<string>();
|
|
743
765
|
const disabled = new Set(disabledExtensionIds);
|
|
766
|
+
// Environmental failures on a configured entry degrade to recorded errors instead
|
|
767
|
+
// of aborting the whole load, so one unreadable, unresolvable, or pathological
|
|
768
|
+
// entry — including a directory whose entries cannot be resolved — cannot drop
|
|
769
|
+
// every other extension the session would have loaded.
|
|
770
|
+
const discoveryErrors: Array<{ path: string; error: string }> = [];
|
|
744
771
|
|
|
745
772
|
const isDisabledName = (name: string): boolean => disabled.has(`extension-module:${name}`);
|
|
746
773
|
|
|
747
774
|
const addPath = (extPath: string): void => {
|
|
775
|
+
if (isDisabledName(getExtensionNameFromPath(extPath))) return;
|
|
748
776
|
const resolved = path.resolve(extPath);
|
|
749
777
|
if (!seen.has(resolved)) {
|
|
750
778
|
seen.add(resolved);
|
|
@@ -753,44 +781,77 @@ export async function discoverAndLoadExtensions(
|
|
|
753
781
|
};
|
|
754
782
|
|
|
755
783
|
const addPaths = (paths: string[]) => {
|
|
756
|
-
for (const extPath of paths)
|
|
757
|
-
if (isDisabledName(getExtensionNameFromPath(extPath))) continue;
|
|
758
|
-
addPath(extPath);
|
|
759
|
-
}
|
|
784
|
+
for (const extPath of paths) addPath(extPath);
|
|
760
785
|
};
|
|
761
786
|
|
|
762
787
|
// 1. Discover extension modules via capability API (native .gjc/.pi only)
|
|
763
|
-
const discovered = await loadCapability<ExtensionModule>(extensionModuleCapability.id, {
|
|
788
|
+
const discovered = await loadCapability<ExtensionModule>(extensionModuleCapability.id, {
|
|
789
|
+
cwd,
|
|
790
|
+
...(options.agentDir === undefined ? {} : { agentDir: options.agentDir }),
|
|
791
|
+
...(options.profileAuthority === undefined ? {} : { profileAuthority: options.profileAuthority }),
|
|
792
|
+
...(options.settings === undefined ? {} : { settings: options.settings }),
|
|
793
|
+
});
|
|
764
794
|
for (const ext of discovered.items) {
|
|
765
795
|
if (ext._source.provider !== "native") continue;
|
|
766
|
-
if (isDisabledName(ext.name)) continue;
|
|
767
796
|
addPath(ext.path);
|
|
768
797
|
}
|
|
769
798
|
|
|
770
799
|
// 2. Discover extension entry points from installed plugins
|
|
771
|
-
|
|
800
|
+
try {
|
|
801
|
+
addPaths(await getAllPluginExtensionPaths(cwd));
|
|
802
|
+
} catch (error) {
|
|
803
|
+
discoveryErrors.push({
|
|
804
|
+
path: "<plugin-registry>",
|
|
805
|
+
error: `Failed to read plugin extension paths: ${safeErrorDescription(error)}`,
|
|
806
|
+
});
|
|
807
|
+
logger.warn("Failed to read plugin extension paths", { error: safeErrorDescription(error) });
|
|
808
|
+
}
|
|
772
809
|
|
|
773
810
|
// 3. Explicitly configured paths
|
|
774
811
|
for (const configuredPath of configuredPaths) {
|
|
775
|
-
|
|
776
|
-
|
|
812
|
+
let resolved: string;
|
|
813
|
+
try {
|
|
814
|
+
resolved = resolvePath(configuredPath, cwd);
|
|
815
|
+
} catch (error) {
|
|
816
|
+
discoveryErrors.push({
|
|
817
|
+
path: safeErrorDescription(configuredPath),
|
|
818
|
+
error: `Failed to resolve extension path: ${safeErrorDescription(error)}`,
|
|
819
|
+
});
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
777
822
|
let stat: fs1.Stats | null = null;
|
|
778
823
|
try {
|
|
779
824
|
stat = await fs.stat(resolved);
|
|
780
825
|
} catch (err) {
|
|
781
|
-
if (!isEnoent(err))
|
|
826
|
+
if (!isEnoent(err)) {
|
|
827
|
+
discoveryErrors.push({
|
|
828
|
+
path: resolved,
|
|
829
|
+
error: `Failed to inspect extension path: ${safeErrorDescription(err)}`,
|
|
830
|
+
});
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
782
833
|
}
|
|
783
834
|
|
|
784
835
|
if (stat?.isDirectory()) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
836
|
+
try {
|
|
837
|
+
const entries = await resolveExtensionEntries(resolved);
|
|
838
|
+
if (entries) {
|
|
839
|
+
addPaths(entries);
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
790
842
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
843
|
+
const discovered = await discoverExtensionsInDir(resolved);
|
|
844
|
+
if (discovered.length > 0) {
|
|
845
|
+
addPaths(discovered);
|
|
846
|
+
}
|
|
847
|
+
} catch (error) {
|
|
848
|
+
// Directory entry resolution rethrows non-ENOENT/EACCES/EPERM faults
|
|
849
|
+
// (ELOOP, ENAMETOOLONG, EIO). Record the offending directory and keep the
|
|
850
|
+
// modules every other source contributes instead of aborting the pass.
|
|
851
|
+
discoveryErrors.push({
|
|
852
|
+
path: resolved,
|
|
853
|
+
error: `Failed to inspect extension entries: ${safeErrorDescription(error)}`,
|
|
854
|
+
});
|
|
794
855
|
}
|
|
795
856
|
continue;
|
|
796
857
|
}
|
|
@@ -798,5 +859,6 @@ export async function discoverAndLoadExtensions(
|
|
|
798
859
|
addPath(resolved);
|
|
799
860
|
}
|
|
800
861
|
|
|
801
|
-
|
|
862
|
+
const result = await loadExtensions(allPaths, cwd, eventBus);
|
|
863
|
+
return discoveryErrors.length === 0 ? result : { ...result, errors: [...discoveryErrors, ...result.errors] };
|
|
802
864
|
}
|