@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/builtin.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { registerProvider } from "../capability";
|
|
|
10
10
|
import { type ContextFile, contextFileCapability } from "../capability/context-file";
|
|
11
11
|
import { type Extension, type ExtensionManifest, extensionCapability } from "../capability/extension";
|
|
12
12
|
import { type ExtensionModule, extensionModuleCapability } from "../capability/extension-module";
|
|
13
|
-
import { readDirEntries, readFile } from "../capability/fs";
|
|
13
|
+
import { isSingleLinkRegularFileAt, type ReadScope, readDirEntries, readFile } from "../capability/fs";
|
|
14
14
|
import { type Hook, hookCapability } from "../capability/hook";
|
|
15
15
|
import { type Instruction, instructionCapability } from "../capability/instruction";
|
|
16
16
|
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
@@ -25,11 +25,13 @@ import type { LoadContext, LoadResult } from "../capability/types";
|
|
|
25
25
|
import { expandTilde } from "../tools/path-utils";
|
|
26
26
|
import {
|
|
27
27
|
buildRuleFromMarkdown,
|
|
28
|
+
canonicalizePathWithinHome,
|
|
28
29
|
createSourceMeta,
|
|
29
30
|
discoverExtensionModulePaths,
|
|
30
31
|
expandEnvVarsDeep,
|
|
31
32
|
getAncestorDirs,
|
|
32
33
|
getExtensionNameFromPath,
|
|
34
|
+
getReadOptions,
|
|
33
35
|
getUserSkillScanDirs,
|
|
34
36
|
loadFilesFromDir,
|
|
35
37
|
readContainedFile,
|
|
@@ -58,17 +60,41 @@ function resolveUserAgentDir(ctx: LoadContext): string {
|
|
|
58
60
|
return ctx.userAgentDir ?? path.join(ctx.home, PATHS.userAgent);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
function readScopeForLevel(level: "user" | "project"): ReadScope {
|
|
64
|
+
return level === "user" ? "native" : "project";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function canonicalBuiltinPath(ctx: LoadContext, filePath: string, scope: ReadScope): Promise<string | null> {
|
|
68
|
+
return (await canonicalizePathWithinHome(ctx, filePath, undefined, scope)) ?? null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function readBuiltinFile(ctx: LoadContext, filePath: string, scope: ReadScope): Promise<string | null> {
|
|
72
|
+
const canonicalPath = await canonicalBuiltinPath(ctx, filePath, scope);
|
|
73
|
+
if (!canonicalPath) return null;
|
|
74
|
+
return readFile(canonicalPath, getReadOptions(ctx, scope));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getProjectStopDirectory(ctx: LoadContext): string | undefined {
|
|
78
|
+
if (ctx.repoRoot) return ctx.repoRoot;
|
|
79
|
+
const homeRelative = path.relative(ctx.home, ctx.cwd);
|
|
80
|
+
const cwdIsWithinHome =
|
|
81
|
+
homeRelative === "" ||
|
|
82
|
+
(homeRelative !== ".." && !homeRelative.startsWith(`..${path.sep}`) && !path.isAbsolute(homeRelative));
|
|
83
|
+
return ctx.isolatedHome || cwdIsWithinHome ? ctx.home : undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
61
86
|
function getProjectConfigDirs(): string[] {
|
|
62
|
-
|
|
87
|
+
// Native project configuration is always rooted at `.gjc`. The configured
|
|
88
|
+
// config-dir name redirects the user profile only; allowing it to rewrite a
|
|
89
|
+
// project path would make explicit-home preflight and discovery disagree.
|
|
90
|
+
return [".gjc"];
|
|
63
91
|
}
|
|
64
92
|
|
|
65
|
-
async function ifNonEmptyDir(...seg: string[]): Promise<string | null> {
|
|
66
|
-
|
|
67
|
-
|
|
93
|
+
async function ifNonEmptyDir(ctx: LoadContext, scope: ReadScope, ...seg: string[]): Promise<string | null> {
|
|
94
|
+
const dir = await canonicalBuiltinPath(ctx, path.join(...seg), scope);
|
|
95
|
+
if (!dir) return null;
|
|
96
|
+
const entries = await readDirEntries(dir, getReadOptions(ctx, scope));
|
|
68
97
|
if (entries.length > 0) {
|
|
69
|
-
if (!path.isAbsolute(dir)) {
|
|
70
|
-
dir = path.resolve(dir);
|
|
71
|
-
}
|
|
72
98
|
return dir;
|
|
73
99
|
}
|
|
74
100
|
return null;
|
|
@@ -78,12 +104,12 @@ async function getConfigDirs(ctx: LoadContext): Promise<Array<{ dir: string; lev
|
|
|
78
104
|
const result: Array<{ dir: string; level: "user" | "project" }> = [];
|
|
79
105
|
|
|
80
106
|
for (const projectConfigDir of getProjectConfigDirs()) {
|
|
81
|
-
const projectDir = await ifNonEmptyDir(ctx.cwd, projectConfigDir);
|
|
107
|
+
const projectDir = await ifNonEmptyDir(ctx, "project", ctx.cwd, projectConfigDir);
|
|
82
108
|
if (projectDir) {
|
|
83
109
|
result.push({ dir: projectDir, level: "project" });
|
|
84
110
|
}
|
|
85
111
|
}
|
|
86
|
-
const userDir = await ifNonEmptyDir(resolveUserAgentDir(ctx));
|
|
112
|
+
const userDir = await ifNonEmptyDir(ctx, "native", resolveUserAgentDir(ctx));
|
|
87
113
|
if (userDir) {
|
|
88
114
|
result.push({ dir: userDir, level: "user" });
|
|
89
115
|
}
|
|
@@ -91,14 +117,10 @@ async function getConfigDirs(ctx: LoadContext): Promise<Array<{ dir: string; lev
|
|
|
91
117
|
return result;
|
|
92
118
|
}
|
|
93
119
|
|
|
94
|
-
async function findNearestProjectConfigDir(
|
|
95
|
-
cwd
|
|
96
|
-
repoRoot?: string | null,
|
|
97
|
-
home?: string,
|
|
98
|
-
): Promise<{ dir: string; depth: number } | null> {
|
|
99
|
-
for (const ancestor of getAncestorDirs(cwd, repoRoot ?? home, home)) {
|
|
120
|
+
async function findNearestProjectConfigDir(ctx: LoadContext): Promise<{ dir: string; depth: number } | null> {
|
|
121
|
+
for (const ancestor of getAncestorDirs(ctx.cwd, getProjectStopDirectory(ctx))) {
|
|
100
122
|
for (const projectConfigDir of getProjectConfigDirs()) {
|
|
101
|
-
const configDir = await ifNonEmptyDir(ancestor.dir, projectConfigDir);
|
|
123
|
+
const configDir = await ifNonEmptyDir(ctx, "project", ancestor.dir, projectConfigDir);
|
|
102
124
|
if (configDir) return { dir: configDir, depth: ancestor.depth };
|
|
103
125
|
}
|
|
104
126
|
}
|
|
@@ -235,11 +257,11 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
235
257
|
|
|
236
258
|
const contents = await Promise.allSettled(
|
|
237
259
|
paths.map(async p => {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return null;
|
|
260
|
+
const scope = readScopeForLevel(p.level);
|
|
261
|
+
const canonicalPath = await canonicalBuiltinPath(ctx, p.path, scope);
|
|
262
|
+
if (!canonicalPath) return null;
|
|
263
|
+
const content = await readBuiltinFile(ctx, canonicalPath, scope);
|
|
264
|
+
return content ? { path: canonicalPath, content, level: p.level } : null;
|
|
243
265
|
}),
|
|
244
266
|
);
|
|
245
267
|
|
|
@@ -265,11 +287,9 @@ registerProvider<MCPServer>(mcpCapability.id, {
|
|
|
265
287
|
async function loadSystemPrompt(ctx: LoadContext): Promise<LoadResult<SystemPrompt>> {
|
|
266
288
|
const items: SystemPrompt[] = [];
|
|
267
289
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const userPath = path.join(resolveUserAgentDir(ctx), "SYSTEM.md");
|
|
272
|
-
const userContent = await readContainedFile(resolveUserAgentDir(ctx), userPath);
|
|
290
|
+
const userAgentDir = resolveUserAgentDir(ctx);
|
|
291
|
+
const userPath = path.join(userAgentDir, "SYSTEM.md");
|
|
292
|
+
const userContent = await readContainedFile(userAgentDir, userPath, ctx.userAgentIdentity);
|
|
273
293
|
if (userContent) {
|
|
274
294
|
items.push({
|
|
275
295
|
path: userPath,
|
|
@@ -279,10 +299,15 @@ async function loadSystemPrompt(ctx: LoadContext): Promise<LoadResult<SystemProm
|
|
|
279
299
|
});
|
|
280
300
|
}
|
|
281
301
|
|
|
282
|
-
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx
|
|
302
|
+
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
|
|
283
303
|
if (nearestProjectConfigDir) {
|
|
284
|
-
const projectPath =
|
|
285
|
-
|
|
304
|
+
const projectPath = await canonicalBuiltinPath(
|
|
305
|
+
ctx,
|
|
306
|
+
path.join(nearestProjectConfigDir.dir, "SYSTEM.md"),
|
|
307
|
+
"project",
|
|
308
|
+
);
|
|
309
|
+
if (!projectPath) return { items, warnings: [] };
|
|
310
|
+
const projectContent = await readBuiltinFile(ctx, projectPath, "project");
|
|
286
311
|
if (projectContent) {
|
|
287
312
|
items.push({
|
|
288
313
|
path: projectPath,
|
|
@@ -307,13 +332,17 @@ registerProvider<SystemPrompt>(systemPromptCapability.id, {
|
|
|
307
332
|
// Skills
|
|
308
333
|
async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
|
|
309
334
|
// Walk up from cwd finding .gjc/skills/ in ancestors (closest first)
|
|
310
|
-
const ancestors = getAncestorDirs(ctx.cwd, ctx.
|
|
335
|
+
const ancestors = getAncestorDirs(ctx.cwd, getProjectStopDirectory(ctx)).filter(
|
|
336
|
+
({ dir }) => path.resolve(dir) !== path.resolve(ctx.home),
|
|
337
|
+
);
|
|
311
338
|
const projectScans = ancestors.flatMap(({ dir }) =>
|
|
312
339
|
getProjectConfigDirs().map(projectConfigDir =>
|
|
313
340
|
scanSkillsFromDir(ctx, {
|
|
314
341
|
dir: path.join(dir, projectConfigDir, "skills"),
|
|
342
|
+
linkContainmentRoot: ctx.repoRoot ?? undefined,
|
|
315
343
|
providerId: PROVIDER_ID,
|
|
316
344
|
level: "project",
|
|
345
|
+
scope: "project",
|
|
317
346
|
requireDescription: true,
|
|
318
347
|
}),
|
|
319
348
|
),
|
|
@@ -328,6 +357,7 @@ async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
|
|
|
328
357
|
authorityRoot: path.resolve(dir) === path.resolve(userAgentDir, "skills") ? userAgentDir : undefined,
|
|
329
358
|
providerId: PROVIDER_ID,
|
|
330
359
|
level: "user",
|
|
360
|
+
scope: "native",
|
|
331
361
|
requireDescription: true,
|
|
332
362
|
}),
|
|
333
363
|
);
|
|
@@ -357,6 +387,7 @@ async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashComm
|
|
|
357
387
|
const commandsDir = path.join(dir, "commands");
|
|
358
388
|
const result = await loadFilesFromDir<SlashCommand>(ctx, commandsDir, PROVIDER_ID, level, {
|
|
359
389
|
extensions: ["md"],
|
|
390
|
+
scope: readScopeForLevel(level),
|
|
360
391
|
transform: (name, content, path, source) => ({
|
|
361
392
|
name: name.replace(/\.md$/, ""),
|
|
362
393
|
path,
|
|
@@ -393,6 +424,7 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
393
424
|
const rulesDir = path.join(dir, "rules");
|
|
394
425
|
const result = await loadFilesFromDir<Rule>(ctx, rulesDir, PROVIDER_ID, level, {
|
|
395
426
|
extensions: ["md", "mdc"],
|
|
427
|
+
scope: readScopeForLevel(level),
|
|
396
428
|
transform: (name, content, path, source) =>
|
|
397
429
|
buildRuleFromMarkdown(name, content, path, source, { stripNamePattern: /\.(md|mdc)$/ }),
|
|
398
430
|
});
|
|
@@ -410,13 +442,12 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
410
442
|
await loadRulesFromDirs([...projectConfigDirs, ...userConfigDirs]);
|
|
411
443
|
|
|
412
444
|
const userRulesFile = path.join(resolveUserAgentDir(ctx), "RULES.md");
|
|
413
|
-
const userRule = await loadStickyRulesFile(userRulesFile, "user");
|
|
445
|
+
const userRule = await loadStickyRulesFile(ctx, userRulesFile, "user");
|
|
414
446
|
if (userRule) items.push(userRule);
|
|
415
|
-
|
|
416
|
-
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx.cwd, ctx.repoRoot, ctx.home);
|
|
447
|
+
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
|
|
417
448
|
if (nearestProjectConfigDir) {
|
|
418
449
|
const projectRulesFile = path.join(nearestProjectConfigDir.dir, "RULES.md");
|
|
419
|
-
const projectRule = await loadStickyRulesFile(projectRulesFile, "project");
|
|
450
|
+
const projectRule = await loadStickyRulesFile(ctx, projectRulesFile, "project");
|
|
420
451
|
if (projectRule) items.push(projectRule);
|
|
421
452
|
}
|
|
422
453
|
|
|
@@ -427,11 +458,21 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
|
|
|
427
458
|
* Read a top-level `RULES.md` and synthesize an always-apply rule.
|
|
428
459
|
* Returns null when the file is absent or empty so callers can short-circuit.
|
|
429
460
|
*/
|
|
430
|
-
async function loadStickyRulesFile(
|
|
431
|
-
|
|
461
|
+
async function loadStickyRulesFile(
|
|
462
|
+
ctx: LoadContext,
|
|
463
|
+
filePath: string,
|
|
464
|
+
level: "user" | "project",
|
|
465
|
+
): Promise<Rule | null> {
|
|
466
|
+
const scope = readScopeForLevel(level);
|
|
467
|
+
const canonicalPath = level === "user" ? filePath : await canonicalBuiltinPath(ctx, filePath, scope);
|
|
468
|
+
if (!canonicalPath) return null;
|
|
469
|
+
const content =
|
|
470
|
+
level === "user"
|
|
471
|
+
? await readContainedFile(path.dirname(filePath), filePath, ctx.userAgentIdentity)
|
|
472
|
+
: await readBuiltinFile(ctx, canonicalPath, scope);
|
|
432
473
|
if (!content) return null;
|
|
433
|
-
const source = createSourceMeta(PROVIDER_ID,
|
|
434
|
-
const rule = buildRuleFromMarkdown("RULES.md", content,
|
|
474
|
+
const source = createSourceMeta(PROVIDER_ID, canonicalPath, level);
|
|
475
|
+
const rule = buildRuleFromMarkdown("RULES.md", content, canonicalPath, source, { ruleName: "RULES" });
|
|
435
476
|
// Force alwaysApply regardless of frontmatter — the whole point of RULES.md
|
|
436
477
|
// is to be reattached every turn.
|
|
437
478
|
return { ...rule, alwaysApply: true };
|
|
@@ -454,6 +495,7 @@ async function loadPrompts(ctx: LoadContext): Promise<LoadResult<Prompt>> {
|
|
|
454
495
|
const promptsDir = path.join(dir, "prompts");
|
|
455
496
|
const result = await loadFilesFromDir<Prompt>(ctx, promptsDir, PROVIDER_ID, level, {
|
|
456
497
|
extensions: ["md"],
|
|
498
|
+
scope: readScopeForLevel(level),
|
|
457
499
|
transform: (name, content, path, source) => ({
|
|
458
500
|
name: name.replace(/\.md$/, ""),
|
|
459
501
|
path,
|
|
@@ -481,12 +523,10 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
481
523
|
const items: ExtensionModule[] = [];
|
|
482
524
|
const warnings: string[] = [];
|
|
483
525
|
|
|
484
|
-
const resolveExtensionPath = (rawPath: string): string => {
|
|
526
|
+
const resolveExtensionPath = async (rawPath: string, scope: ReadScope): Promise<string | undefined> => {
|
|
485
527
|
const expanded = expandTilde(rawPath, ctx.home);
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
489
|
-
return path.resolve(ctx.cwd, expanded);
|
|
528
|
+
const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(ctx.cwd, expanded);
|
|
529
|
+
return await canonicalizePathWithinHome(ctx, resolved, undefined, scope);
|
|
490
530
|
};
|
|
491
531
|
|
|
492
532
|
const createExtensionModule = (extPath: string, level: "user" | "project"): ExtensionModule => ({
|
|
@@ -499,8 +539,18 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
499
539
|
const configDirs = await getConfigDirs(ctx);
|
|
500
540
|
|
|
501
541
|
const [discoveredResults, settingsResults] = await Promise.all([
|
|
502
|
-
Promise.all(
|
|
503
|
-
|
|
542
|
+
Promise.all(
|
|
543
|
+
configDirs.map(({ dir, level }) =>
|
|
544
|
+
discoverExtensionModulePaths(ctx, path.join(dir, "extensions"), {
|
|
545
|
+
scope: readScopeForLevel(level),
|
|
546
|
+
}),
|
|
547
|
+
),
|
|
548
|
+
),
|
|
549
|
+
Promise.all(
|
|
550
|
+
configDirs.map(({ dir, level }) =>
|
|
551
|
+
readBuiltinFile(ctx, path.join(dir, "settings.json"), readScopeForLevel(level)),
|
|
552
|
+
),
|
|
553
|
+
),
|
|
504
554
|
]);
|
|
505
555
|
|
|
506
556
|
for (let i = 0; i < configDirs.length; i++) {
|
|
@@ -531,8 +581,13 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
531
581
|
warnings.push(`Invalid extension path in ${settingsPath}: ${String(entry)}`);
|
|
532
582
|
continue;
|
|
533
583
|
}
|
|
584
|
+
const resolvedPath = await resolveExtensionPath(entry, readScopeForLevel(level));
|
|
585
|
+
if (!resolvedPath) {
|
|
586
|
+
warnings.push(`Extension path escapes isolated home in ${settingsPath}: ${entry}`);
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
534
589
|
settingsExtensions.push({
|
|
535
|
-
resolvedPath
|
|
590
|
+
resolvedPath,
|
|
536
591
|
settingsPath,
|
|
537
592
|
level,
|
|
538
593
|
});
|
|
@@ -540,8 +595,16 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
540
595
|
}
|
|
541
596
|
|
|
542
597
|
const [entriesResults, fileContents] = await Promise.all([
|
|
543
|
-
Promise.all(
|
|
544
|
-
|
|
598
|
+
Promise.all(
|
|
599
|
+
settingsExtensions.map(({ resolvedPath, level }) =>
|
|
600
|
+
readDirEntries(resolvedPath, getReadOptions(ctx, readScopeForLevel(level))),
|
|
601
|
+
),
|
|
602
|
+
),
|
|
603
|
+
Promise.all(
|
|
604
|
+
settingsExtensions.map(({ resolvedPath, level }) =>
|
|
605
|
+
readBuiltinFile(ctx, resolvedPath, readScopeForLevel(level)),
|
|
606
|
+
),
|
|
607
|
+
),
|
|
545
608
|
]);
|
|
546
609
|
|
|
547
610
|
const dirDiscoveryPromises: Array<{
|
|
@@ -556,7 +619,9 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
|
|
|
556
619
|
|
|
557
620
|
if (entries.length > 0) {
|
|
558
621
|
dirDiscoveryPromises.push({
|
|
559
|
-
promise: discoverExtensionModulePaths(ctx, resolvedPath
|
|
622
|
+
promise: discoverExtensionModulePaths(ctx, resolvedPath, {
|
|
623
|
+
scope: readScopeForLevel(level),
|
|
624
|
+
}),
|
|
560
625
|
level,
|
|
561
626
|
});
|
|
562
627
|
} else if (content !== null) {
|
|
@@ -591,7 +656,11 @@ async function loadExtensions(ctx: LoadContext): Promise<LoadResult<Extension>>
|
|
|
591
656
|
const warnings: string[] = [];
|
|
592
657
|
|
|
593
658
|
const configDirs = await getConfigDirs(ctx);
|
|
594
|
-
const entriesResults = await Promise.all(
|
|
659
|
+
const entriesResults = await Promise.all(
|
|
660
|
+
configDirs.map(({ dir, level }) =>
|
|
661
|
+
readDirEntries(path.join(dir, "extensions"), getReadOptions(ctx, readScopeForLevel(level))),
|
|
662
|
+
),
|
|
663
|
+
);
|
|
595
664
|
|
|
596
665
|
const manifestCandidates: Array<{
|
|
597
666
|
extDir: string;
|
|
@@ -609,17 +678,23 @@ async function loadExtensions(ctx: LoadContext): Promise<LoadResult<Extension>>
|
|
|
609
678
|
if (entry.name.startsWith(".")) continue;
|
|
610
679
|
if (!entry.isDirectory()) continue;
|
|
611
680
|
|
|
612
|
-
const
|
|
681
|
+
const scope = readScopeForLevel(level);
|
|
682
|
+
const extDir = await canonicalBuiltinPath(ctx, path.join(extensionsDir, entry.name), scope);
|
|
683
|
+
if (!extDir) continue;
|
|
684
|
+
const manifestPath = await canonicalBuiltinPath(ctx, path.join(extDir, "gemini-extension.json"), scope);
|
|
685
|
+
if (!manifestPath) continue;
|
|
613
686
|
manifestCandidates.push({
|
|
614
687
|
extDir,
|
|
615
|
-
manifestPath
|
|
688
|
+
manifestPath,
|
|
616
689
|
entryName: entry.name,
|
|
617
690
|
level,
|
|
618
691
|
});
|
|
619
692
|
}
|
|
620
693
|
}
|
|
621
694
|
|
|
622
|
-
const manifestContents = await Promise.all(
|
|
695
|
+
const manifestContents = await Promise.all(
|
|
696
|
+
manifestCandidates.map(({ manifestPath, level }) => readBuiltinFile(ctx, manifestPath, readScopeForLevel(level))),
|
|
697
|
+
);
|
|
623
698
|
|
|
624
699
|
for (let i = 0; i < manifestCandidates.length; i++) {
|
|
625
700
|
const content = manifestContents[i];
|
|
@@ -661,6 +736,7 @@ async function loadInstructions(ctx: LoadContext): Promise<LoadResult<Instructio
|
|
|
661
736
|
const instructionsDir = path.join(dir, "instructions");
|
|
662
737
|
const result = await loadFilesFromDir<Instruction>(ctx, instructionsDir, PROVIDER_ID, level, {
|
|
663
738
|
extensions: ["md"],
|
|
739
|
+
scope: readScopeForLevel(level),
|
|
664
740
|
transform: (name, content, path, source) => {
|
|
665
741
|
const { frontmatter, body } = parseFrontmatter(content, { source: path });
|
|
666
742
|
return {
|
|
@@ -702,15 +778,22 @@ async function loadHooks(ctx: LoadContext): Promise<LoadResult<Hook>> {
|
|
|
702
778
|
|
|
703
779
|
for (const { dir, level } of configDirs) {
|
|
704
780
|
for (const hookType of hookTypes) {
|
|
781
|
+
const scope = readScopeForLevel(level);
|
|
782
|
+
const typeDir = await canonicalBuiltinPath(ctx, path.join(dir, "hooks", hookType), scope);
|
|
783
|
+
if (!typeDir) continue;
|
|
705
784
|
typeDirRequests.push({
|
|
706
|
-
typeDir
|
|
785
|
+
typeDir,
|
|
707
786
|
hookType,
|
|
708
787
|
level,
|
|
709
788
|
});
|
|
710
789
|
}
|
|
711
790
|
}
|
|
712
791
|
|
|
713
|
-
const typeEntriesResults = await Promise.all(
|
|
792
|
+
const typeEntriesResults = await Promise.all(
|
|
793
|
+
typeDirRequests.map(({ typeDir, level }) =>
|
|
794
|
+
readDirEntries(typeDir, getReadOptions(ctx, readScopeForLevel(level))),
|
|
795
|
+
),
|
|
796
|
+
);
|
|
714
797
|
|
|
715
798
|
for (let i = 0; i < typeDirRequests.length; i++) {
|
|
716
799
|
const { typeDir, hookType, level } = typeDirRequests[i];
|
|
@@ -720,7 +803,9 @@ async function loadHooks(ctx: LoadContext): Promise<LoadResult<Hook>> {
|
|
|
720
803
|
if (entry.name.startsWith(".")) continue;
|
|
721
804
|
if (!entry.isFile()) continue;
|
|
722
805
|
|
|
723
|
-
const hookPath = path.join(typeDir, entry.name);
|
|
806
|
+
const hookPath = await canonicalBuiltinPath(ctx, path.join(typeDir, entry.name), readScopeForLevel(level));
|
|
807
|
+
if (!hookPath) continue;
|
|
808
|
+
if (ctx.isolatedHome && !(await isSingleLinkRegularFileAt(hookPath))) continue;
|
|
724
809
|
const baseName = entry.name.includes(".") ? entry.name.slice(0, entry.name.lastIndexOf(".")) : entry.name;
|
|
725
810
|
const tool = baseName === "*" ? "*" : baseName;
|
|
726
811
|
|
|
@@ -752,7 +837,16 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
752
837
|
const warnings: string[] = [];
|
|
753
838
|
|
|
754
839
|
const configDirs = await getConfigDirs(ctx);
|
|
755
|
-
const
|
|
840
|
+
const toolsDirs = await Promise.all(
|
|
841
|
+
configDirs.map(({ dir, level }) => canonicalBuiltinPath(ctx, path.join(dir, "tools"), readScopeForLevel(level))),
|
|
842
|
+
);
|
|
843
|
+
const entriesResults = await Promise.all(
|
|
844
|
+
toolsDirs.map((toolsDir, i) =>
|
|
845
|
+
toolsDir
|
|
846
|
+
? readDirEntries(toolsDir, getReadOptions(ctx, readScopeForLevel(configDirs[i].level)))
|
|
847
|
+
: Promise.resolve([]),
|
|
848
|
+
),
|
|
849
|
+
);
|
|
756
850
|
|
|
757
851
|
const fileLoadPromises: Array<Promise<{ items: CustomTool[]; warnings?: string[] }>> = [];
|
|
758
852
|
const subDirCandidates: Array<{
|
|
@@ -762,15 +856,15 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
762
856
|
}> = [];
|
|
763
857
|
|
|
764
858
|
for (let i = 0; i < configDirs.length; i++) {
|
|
765
|
-
const {
|
|
859
|
+
const { level } = configDirs[i];
|
|
766
860
|
const toolEntries = entriesResults[i];
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const toolsDir = path.join(dir, "tools");
|
|
861
|
+
const toolsDir = toolsDirs[i];
|
|
862
|
+
if (toolEntries.length === 0 || !toolsDir) continue;
|
|
770
863
|
|
|
771
864
|
fileLoadPromises.push(
|
|
772
865
|
loadFilesFromDir<CustomTool>(ctx, toolsDir, PROVIDER_ID, level, {
|
|
773
866
|
extensions: ["json", "md", "ts", "js", "sh", "bash", "py"],
|
|
867
|
+
scope: readScopeForLevel(level),
|
|
774
868
|
transform: (name, content, path, source) => {
|
|
775
869
|
if (name.endsWith(".json")) {
|
|
776
870
|
const data = tryParseJson<{ name?: string; description?: string }>(content);
|
|
@@ -819,8 +913,14 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
819
913
|
if (entry.name.startsWith(".")) continue;
|
|
820
914
|
if (!entry.isDirectory()) continue;
|
|
821
915
|
|
|
916
|
+
const indexPath = await canonicalBuiltinPath(
|
|
917
|
+
ctx,
|
|
918
|
+
path.join(toolsDir, entry.name, "index.ts"),
|
|
919
|
+
readScopeForLevel(level),
|
|
920
|
+
);
|
|
921
|
+
if (!indexPath) continue;
|
|
822
922
|
subDirCandidates.push({
|
|
823
|
-
indexPath
|
|
923
|
+
indexPath,
|
|
824
924
|
entryName: entry.name,
|
|
825
925
|
level,
|
|
826
926
|
});
|
|
@@ -829,7 +929,9 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
829
929
|
|
|
830
930
|
const [fileResults, indexContents] = await Promise.all([
|
|
831
931
|
Promise.all(fileLoadPromises),
|
|
832
|
-
Promise.all(
|
|
932
|
+
Promise.all(
|
|
933
|
+
subDirCandidates.map(({ indexPath, level }) => readBuiltinFile(ctx, indexPath, readScopeForLevel(level))),
|
|
934
|
+
),
|
|
833
935
|
]);
|
|
834
936
|
|
|
835
937
|
for (const result of fileResults) {
|
|
@@ -879,9 +981,10 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
|
|
|
879
981
|
};
|
|
880
982
|
|
|
881
983
|
for (const { dir, level } of await getConfigDirs(ctx)) {
|
|
882
|
-
const
|
|
883
|
-
const
|
|
884
|
-
|
|
984
|
+
const scope = readScopeForLevel(level);
|
|
985
|
+
const settingsPath = await canonicalBuiltinPath(ctx, path.join(dir, "settings.json"), scope);
|
|
986
|
+
const settingsContent = settingsPath ? await readBuiltinFile(ctx, settingsPath, scope) : null;
|
|
987
|
+
if (settingsContent && settingsPath) {
|
|
885
988
|
const data = tryParseJson<Record<string, unknown>>(settingsContent);
|
|
886
989
|
if (data) {
|
|
887
990
|
items.push({
|
|
@@ -895,8 +998,9 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
|
|
|
895
998
|
}
|
|
896
999
|
}
|
|
897
1000
|
|
|
898
|
-
const configPath = path.join(dir, "config.yml");
|
|
899
|
-
|
|
1001
|
+
const configPath = await canonicalBuiltinPath(ctx, path.join(dir, "config.yml"), scope);
|
|
1002
|
+
if (!configPath) continue;
|
|
1003
|
+
const configContent = await readBuiltinFile(ctx, configPath, scope);
|
|
900
1004
|
if (!configContent) continue;
|
|
901
1005
|
|
|
902
1006
|
const data = parseYamlSettings(configContent, configPath);
|
|
@@ -926,8 +1030,9 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
|
|
|
926
1030
|
const items: ContextFile[] = [];
|
|
927
1031
|
const warnings: string[] = [];
|
|
928
1032
|
|
|
929
|
-
const
|
|
930
|
-
const
|
|
1033
|
+
const userAgentDir = resolveUserAgentDir(ctx);
|
|
1034
|
+
const userPath = path.join(userAgentDir, "AGENTS.md");
|
|
1035
|
+
const userContent = await readContainedFile(userAgentDir, userPath, ctx.userAgentIdentity);
|
|
931
1036
|
if (userContent) {
|
|
932
1037
|
items.push({
|
|
933
1038
|
path: userPath,
|
|
@@ -937,11 +1042,15 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
|
|
|
937
1042
|
});
|
|
938
1043
|
}
|
|
939
1044
|
|
|
940
|
-
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx
|
|
1045
|
+
const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
|
|
941
1046
|
if (nearestProjectConfigDir) {
|
|
942
|
-
const projectPath =
|
|
943
|
-
|
|
944
|
-
|
|
1047
|
+
const projectPath = await canonicalBuiltinPath(
|
|
1048
|
+
ctx,
|
|
1049
|
+
path.join(nearestProjectConfigDir.dir, "AGENTS.md"),
|
|
1050
|
+
"project",
|
|
1051
|
+
);
|
|
1052
|
+
const projectContent = projectPath ? await readBuiltinFile(ctx, projectPath, "project") : null;
|
|
1053
|
+
if (projectContent && projectPath) {
|
|
945
1054
|
items.push({
|
|
946
1055
|
path: projectPath,
|
|
947
1056
|
content: projectContent,
|