@gajae-code/coding-agent 0.7.10 → 0.8.0
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 +58 -0
- package/README.md +2 -2
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/config/keybindings.d.ts +11 -5
- package/dist/types/config/settings-schema.d.ts +25 -2
- package/dist/types/defaults/gjc-defaults.d.ts +7 -0
- package/dist/types/discovery/cursor.d.ts +4 -1
- package/dist/types/discovery/index.d.ts +0 -1
- package/dist/types/discovery/windsurf.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +3 -2
- package/dist/types/gjc-runtime/restricted-role-agent-bash.d.ts +1 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +5 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -1
- package/dist/types/modes/components/settings-selector.d.ts +1 -0
- package/dist/types/modes/components/skill-message.d.ts +1 -0
- package/dist/types/modes/components/status-line.d.ts +8 -0
- package/dist/types/modes/components/two-column-body.d.ts +9 -0
- package/dist/types/modes/components/welcome.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +5 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +2 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/types/modes/slash-command-visibility.d.ts +1 -0
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +9 -0
- package/dist/types/runtime-mcp/config.d.ts +2 -0
- package/dist/types/runtime-mcp/loader.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +2 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +8 -5
- package/dist/types/slash-commands/types.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +7 -0
- package/dist/types/utils/cmux-workspace.d.ts +30 -1
- package/dist/types/web/search/index.d.ts +3 -1
- package/dist/types/web/search/provider.d.ts +9 -0
- package/dist/types/web/search/providers/utils.d.ts +42 -13
- package/dist/types/workflow/workflow-intent-diff.d.ts +19 -0
- package/package.json +10 -10
- package/src/capability/mcp.ts +2 -0
- package/src/cli/update-cli.ts +24 -0
- package/src/cli/web-search-cli.ts +2 -5
- package/src/cli.ts +1 -1
- package/src/commands/launch.ts +1 -1
- package/src/commands/ralplan.ts +1 -0
- package/src/config/keybindings.ts +14 -5
- package/src/config/mcp-schema.json +5 -1
- package/src/config/model-profiles.ts +16 -0
- package/src/config/settings-schema.ts +18 -2
- package/src/coordinator-mcp/server.ts +15 -3
- package/src/defaults/gjc/skills/ralplan/SKILL.md +16 -14
- package/src/defaults/gjc-defaults.ts +16 -0
- package/src/discovery/builtin.ts +12 -0
- package/src/discovery/cursor.ts +5 -84
- package/src/discovery/gemini.ts +3 -89
- package/src/discovery/index.ts +4 -1
- package/src/discovery/mcp-json.ts +11 -0
- package/src/discovery/opencode.ts +5 -122
- package/src/discovery/windsurf.ts +4 -82
- package/src/edit/read-file.ts +9 -1
- package/src/extensibility/extensions/runner.ts +2 -1
- package/src/gjc-runtime/launch-tmux.ts +164 -42
- package/src/gjc-runtime/ralplan-runtime.ts +22 -6
- package/src/gjc-runtime/restricted-role-agent-bash.ts +1 -0
- package/src/gjc-runtime/session-state-sidecar.ts +167 -24
- package/src/gjc-runtime/state-runtime.ts +8 -5
- package/src/gjc-runtime/state-writer.ts +5 -5
- package/src/gjc-runtime/team-runtime.ts +56 -51
- package/src/internal-urls/docs-index.generated.ts +8 -7
- package/src/main.ts +2 -2
- package/src/migrate/executor.ts +23 -6
- package/src/modes/components/agent-dashboard.ts +1 -34
- package/src/modes/components/custom-editor.ts +26 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -48
- package/src/modes/components/model-selector.ts +64 -4
- package/src/modes/components/session-selector.ts +19 -9
- package/src/modes/components/settings-selector.ts +13 -2
- package/src/modes/components/skill-message.ts +18 -10
- package/src/modes/components/status-line.ts +215 -86
- package/src/modes/components/tree-selector.ts +28 -8
- package/src/modes/components/two-column-body.ts +36 -0
- package/src/modes/components/welcome.ts +171 -35
- package/src/modes/controllers/command-controller.ts +23 -0
- package/src/modes/controllers/event-controller.ts +4 -0
- package/src/modes/controllers/input-controller.ts +192 -39
- package/src/modes/controllers/selector-controller.ts +25 -28
- package/src/modes/interactive-mode.ts +36 -30
- package/src/modes/prompt-action-autocomplete.ts +23 -1
- package/src/modes/rpc/rpc-types.ts +1 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +9 -3
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +20 -0
- package/src/modes/slash-command-visibility.ts +9 -0
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/hotkeys-markdown.ts +5 -2
- package/src/modes/utils/ui-helpers.ts +76 -3
- package/src/notifications/index.ts +20 -1
- package/src/notifications/lifecycle-control-runtime.ts +12 -3
- package/src/notifications/telegram-daemon.ts +4 -4
- package/src/prompts/agents/architect.md +7 -4
- package/src/prompts/agents/critic.md +15 -6
- package/src/prompts/agents/planner.md +8 -3
- package/src/prompts/system/system-prompt.md +15 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/runtime-mcp/config-writer.ts +28 -0
- package/src/runtime-mcp/config.ts +7 -0
- package/src/runtime-mcp/loader.ts +3 -0
- package/src/runtime-mcp/manager.ts +3 -0
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk.ts +7 -6
- package/src/session/agent-session.ts +81 -18
- package/src/session/session-manager.ts +58 -18
- package/src/slash-commands/builtin-registry.ts +30 -10
- package/src/slash-commands/types.ts +2 -0
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +5 -0
- package/src/tools/ast-grep.ts +10 -7
- package/src/tools/bash.ts +39 -14
- package/src/tools/index.ts +8 -1
- package/src/utils/cmux-workspace.ts +134 -7
- package/src/utils/title-generator.ts +1 -1
- package/src/web/kagi.ts +1 -1
- package/src/web/parallel.ts +2 -2
- package/src/web/search/index.ts +118 -45
- package/src/web/search/provider.ts +65 -0
- package/src/web/search/providers/anthropic.ts +1 -1
- package/src/web/search/providers/brave.ts +1 -1
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/duckduckgo.ts +1 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/gemini.ts +7 -3
- package/src/web/search/providers/jina.ts +1 -1
- package/src/web/search/providers/kimi.ts +6 -1
- package/src/web/search/providers/openai-compatible.ts +1 -1
- package/src/web/search/providers/parallel.ts +1 -1
- package/src/web/search/providers/perplexity.ts +2 -2
- package/src/web/search/providers/searxng.ts +1 -1
- package/src/web/search/providers/synthetic.ts +1 -1
- package/src/web/search/providers/tavily.ts +1 -1
- package/src/web/search/providers/utils.ts +67 -17
- package/src/web/search/providers/xai.ts +1 -1
- package/src/web/search/providers/zai.ts +1 -1
- package/src/workflow/workflow-intent-diff.ts +199 -0
- package/dist/types/discovery/vscode.d.ts +0 -1
- package/src/discovery/vscode.ts +0 -105
|
@@ -45,13 +45,15 @@ Planning artifacts and stage handoffs MUST be persisted through the ralplan CLI
|
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
gjc ralplan --write --stage <type> --stage_n <N> --artifact "markdown file path or markdown string"
|
|
48
|
+
# restricted role agents use:
|
|
49
|
+
gjc ralplan --write --stage <type> --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
Use stage values that match the producer or artifact kind, such as `planner`, `architect`, `critic`, `revision`, `post-interview`, `adr`, or `final`. Increment `--stage_n` for each consensus-loop pass. The `--artifact` value may be either a markdown file path prepared outside `.gjc/` for ingestion or the markdown content string itself. The native `--write` handler persists markdown under `.gjc/_session-{sessionid}/plans/ralplan/<run-id>/stage-<NN>-<stage>.md`, maintains an `index.jsonl` audit log, and for `final` stages additionally writes a `pending-approval.md` copy. Direct `write`, `edit`, or `ast_edit` calls against `.gjc/_session-{sessionid}/specs`, `.gjc/_session-{sessionid}/plans`, `.gjc/_session-{sessionid}/state`, or any other `.gjc/` path are forbidden unless an explicit force override is active.
|
|
52
|
+
Use stage values that match the producer or artifact kind, such as `planner`, `architect`, `critic`, `revision`, `post-interview`, `adr`, or `final`. Increment `--stage_n` for each consensus-loop pass. The `--artifact` value may be either a markdown file path prepared outside `.gjc/` for ingestion or the markdown content string itself. The native `--write` handler also accepts `--artifact-env GJC_RALPLAN_ARTIFACT` to read markdown from that per-command env override. It persists markdown under `.gjc/_session-{sessionid}/plans/ralplan/<run-id>/stage-<NN>-<stage>.md`, maintains an `index.jsonl` audit log, and for `final` stages additionally writes a `pending-approval.md` copy. Direct `write`, `edit`, or `ast_edit` calls against `.gjc/_session-{sessionid}/specs`, `.gjc/_session-{sessionid}/plans`, `.gjc/_session-{sessionid}/state`, or any other `.gjc/` path are forbidden unless an explicit force override is active.
|
|
51
53
|
|
|
52
|
-
While ralplan is active it is a pre-approval planning phase: product-code mutation tools (`write`/`edit`/`ast_edit`) and product-mutating `bash` (e.g. `tee src/...`, redirects into the project tree) are blocked, exactly like deep-interview.
|
|
54
|
+
While ralplan is active it is a pre-approval planning phase: product-code mutation tools (`write`/`edit`/`ast_edit`) and product-mutating `bash` (e.g. `tee src/...`, redirects into the project tree) are blocked, exactly like deep-interview. Leaders may pass `--artifact` markdown inline or, when an artifact is too large to pass inline, stage it as a file in a system temp directory (`os.tmpdir()`/`$TMPDIR`, `/tmp`, `/var/tmp`) outside the project tree and pass that path — never write scratch files into the repo or `.gjc/`. Product code is mutated only after the plan is approved and execution begins.
|
|
53
55
|
|
|
54
|
-
Restricted read-only role agents (`planner`, `architect`, and `critic`) must pass markdown content
|
|
56
|
+
Restricted read-only role agents (`planner`, `architect`, and `critic`) must pass markdown content through the `GJC_RALPLAN_ARTIFACT` env override with `--artifact-env GJC_RALPLAN_ARTIFACT`; their restricted bash environment intentionally disables artifact file-path ingestion so a verdict command cannot persist arbitrary file contents.
|
|
55
57
|
|
|
56
58
|
After a role agent persists a stage artifact, its model-facing response to the caller SHOULD be receipt-only: return the `gjc ralplan --write --json` receipt (`run_id`, `path`, `stage`, `stage_n`, `sha256`, `created_at`) plus the minimal verdict/status fields the caller needs for routing, and do **not** paste the full persisted markdown back into the parent conversation. Downstream reviewers should receive the artifact path/receipt and read the persisted file themselves when they actually need the body. This preserves the audit trail while preventing Planner/Architect/Critic verdict bodies from being duplicated into the main-agent context.
|
|
57
59
|
|
|
@@ -60,7 +62,7 @@ RECEIPT-ONLY guideline: role agents (`planner`, `architect`, and `critic`) persi
|
|
|
60
62
|
This skill runs GJC planning in consensus mode for the provided arguments.
|
|
61
63
|
|
|
62
64
|
The consensus workflow:
|
|
63
|
-
1. **Planner** creates the initial plan and a compact **RALPLAN-DR summary** before review. Launch the Planner ONCE per run as a detached, resumable subagent (await it before the Architect) and record its returned subagent id as the run's persisted Planner id; persist the stage with `gjc ralplan --write --stage planner --stage_n 1 --artifact
|
|
65
|
+
1. **Planner** creates the initial plan and a compact **RALPLAN-DR summary** before review. Launch the Planner ONCE per run as a detached, resumable subagent (await it before the Architect) and record its returned subagent id as the run's persisted Planner id; persist the stage with `gjc ralplan --write --stage planner --stage_n 1 --artifact-env GJC_RALPLAN_ARTIFACT --planner-id <id> --planner-resumable <true|false>` (see **Persisted Planner** below):
|
|
64
66
|
- After persistence, return only the receipt/path plus compact planning status; do not paste the full plan markdown back to the caller unless explicitly requested.
|
|
65
67
|
- Principles (3-5)
|
|
66
68
|
- Decision Drivers (top 3)
|
|
@@ -69,26 +71,26 @@ The consensus workflow:
|
|
|
69
71
|
- Deliberate mode only: pre-mortem (3 scenarios) + expanded test plan (unit/integration/e2e/observability)
|
|
70
72
|
2. **User feedback** *(--interactive only)*: If `--interactive` is set, use the `ask` tool to present the draft plan **plus the Principles / Drivers / Options summary** before review (Proceed to review / Request changes / Skip review). Otherwise, automatically proceed to review.
|
|
71
73
|
3. **Architect** reviews for architectural soundness and must provide the strongest steelman antithesis, at least one real tradeoff tension, and (when possible) synthesis — **await completion before step 4**. In deliberate mode, Architect should explicitly flag principle violations.
|
|
72
|
-
- The Architect agent/subagent must persist its review with `gjc ralplan --write --stage architect --stage_n <N> --artifact
|
|
74
|
+
- The Architect agent/subagent must persist its review with `gjc ralplan --write --stage architect --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT --json`, then return the receipt/path plus compact verdict/status (`CLEAR`/`WATCH`/`BLOCK`, `APPROVE`/`COMMENT`/`REQUEST CHANGES`) instead of pasting the full review body.
|
|
73
75
|
4. **Critic** evaluates against quality criteria — run only after step 3 completes. Critic must enforce principle-option consistency, fair alternatives, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. In deliberate mode, Critic must reject missing/weak pre-mortem or expanded test plan.
|
|
74
|
-
- The Critic agent/subagent must persist its evaluation with `gjc ralplan --write --stage critic --stage_n <N> --artifact
|
|
75
|
-
5. **Re-review loop** (max 5 iterations): Any non-`
|
|
76
|
+
- The Critic agent/subagent must persist its evaluation with `gjc ralplan --write --stage critic --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT --json`, then return the receipt/path plus compact verdict/status (`OKAY`/`ITERATE`/`REJECT`) instead of pasting the full evaluation body.
|
|
77
|
+
5. **Re-review loop** (max 5 iterations): Any non-`OKAY` Critic verdict (`ITERATE` or `REJECT`) MUST run the same full closed loop:
|
|
76
78
|
a. Collect Architect + Critic feedback
|
|
77
79
|
b. Revise the plan by resuming the SAME persisted Planner subagent with consolidated Architect + Critic feedback (see **Persisted Planner** below); fall back to a fresh Planner spawn only per the fallback routing table
|
|
78
80
|
c. Return to Architect review
|
|
79
|
-
- Persist each Planner revision with `gjc ralplan --write --stage revision --stage_n <N> --artifact
|
|
81
|
+
- Persist each Planner revision with `gjc ralplan --write --stage revision --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT --json` before re-review, then pass the receipt/path forward instead of duplicating the full revision markdown in the parent conversation.
|
|
80
82
|
d. Return to Critic evaluation
|
|
81
|
-
e. Repeat this loop until Critic returns `
|
|
82
|
-
f. If 5 iterations are reached without `
|
|
83
|
-
6. **Post-ralplan interview** (intent reconciliation gate): After Critic returns `
|
|
83
|
+
e. Repeat this loop until Critic returns `OKAY` or 5 iterations are reached
|
|
84
|
+
f. If 5 iterations are reached without `OKAY`, present the best version to the user
|
|
85
|
+
6. **Post-ralplan interview** (intent reconciliation gate): After Critic returns `OKAY` and before the plan is finalized, reconcile the consensus plan against the user's actual intent. The goal is to make sure ralplan did not silently bake in assumptions that conflict with what the user wants.
|
|
84
86
|
a. **Collect open items** from the run: every assumption the Planner/Architect/Critic resolved by assumption rather than by stated fact, every ambiguity flagged during review, and every decision the loop made without explicit user input. Source these from the persisted `planner`/`architect`/`critic`/`revision` stage artifacts, not from memory.
|
|
85
87
|
b. **Cross-check prior context for conflicts**: glob `.gjc/_session-{sessionid}/specs/deep-interview-*.md` and other prior specs/plans/context relevant by topic. For each, list points where the consensus plan contradicts, weakens, or expands beyond a previously crystallized decision, constraint, or non-goal. Cite the conflicting artifact and line/section.
|
|
86
88
|
c. **Reconcile with the user via the `ask` tool (always, regardless of `--interactive`)**: Never stop idle with plain-text prose after the consensus loop. Every reconciliation question MUST go through the `ask` tool with contextual options plus free-text.
|
|
87
89
|
- If open items exist, confirm the open assumptions and conflicts **one at a time** with the `ask` tool, weakest/highest-impact first, polishing intent. If any confirmation reveals that the plan diverges from user intent, route the consolidated correction back into the re-review loop (step 5b Planner revision) and re-run Architect + Critic before returning here. Cap at the same 5-iteration ceiling.
|
|
88
90
|
- If the plan is crystal clear (no open assumptions or prior-context conflicts), skip straight to the step 8 final-options `ask` instead of inventing filler questions.
|
|
89
91
|
- For every confirmed open item, embed the resolved outcome into the final plan under an **## Intent Reconciliation** section so the `pending approval` artifact records each decision; record any item the user explicitly defers as an open confirmation under that same section.
|
|
90
|
-
d. Persist the reconciliation with `gjc ralplan --write --stage post-interview --stage_n <N> --artifact
|
|
91
|
-
7. On reconciliation completion, mark the plan `pending approval` unless explicit execution approval has already been captured, persist the ADR/final plan via `gjc ralplan --write --stage final --stage_n <N> --artifact
|
|
92
|
+
d. Persist the reconciliation with `gjc ralplan --write --stage post-interview --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT --json`, then return the receipt/path plus a compact status (reconciled-clean / reconciled-with-revision / open-confirmations-pending) instead of pasting the full body.
|
|
93
|
+
7. On reconciliation completion, mark the plan `pending approval` unless explicit execution approval has already been captured, persist the ADR/final plan via `gjc ralplan --write --stage final --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT`, and do not directly edit `.gjc/_session-{sessionid}/plans`. Final plan must include ADR (Decision, Drivers, Alternatives considered, Why chosen, Consequences, Follow-ups) and, when present, the **## Intent Reconciliation** section.
|
|
92
94
|
8. **Always** present the finalized plan via the `ask` tool (regardless of `--interactive`) with `workflowGate: { stage: "ralplan", kind: "approval" }` on the final question so RPC/headless clients receive a `ralplan`/`approval` workflow gate, not a deep-interview question gate. Use these options:
|
|
93
95
|
- **Refine further** — re-run the consensus loop / request changes, then return here
|
|
94
96
|
- **Approve execution via ultragoal (Recommended)** — goal-tracked autonomous execution
|
|
@@ -128,7 +130,7 @@ The Planner is a **same-session persisted subagent**: launched detached once, aw
|
|
|
128
130
|
**Recording persisted-Planner metadata** (audit/routing only — never claim `subagent list` proves resumability, since the snapshot does not expose `resumable`). Ride these optional flags on the normal `--write` for the planner/revision stage of the pass:
|
|
129
131
|
|
|
130
132
|
```
|
|
131
|
-
gjc ralplan --write --stage revision --stage_n <N> --artifact
|
|
133
|
+
gjc ralplan --write --stage revision --stage_n <N> --artifact-env GJC_RALPLAN_ARTIFACT \
|
|
132
134
|
--planner-id <id> --planner-resumable <true|false> \
|
|
133
135
|
--fallback-reason <context_unavailable|not_found|no_runner|resume_failed|process_restart|missing_record> \
|
|
134
136
|
--fallback-attempted-id <id> --fallback-stage-n <N> \
|
|
@@ -44,6 +44,13 @@ export type DefaultGjcDefinition = DefaultGjcSkillDefinition | DefaultGjcSkillFr
|
|
|
44
44
|
export interface InstallDefaultGjcDefinitionsOptions {
|
|
45
45
|
check?: boolean;
|
|
46
46
|
force?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Only rewrite default definition files that already exist on disk but whose
|
|
49
|
+
* content differs from the embedded defaults. Files that are absent are left
|
|
50
|
+
* absent (status "missing"). Used by `gjc update` to refresh opted-in copies
|
|
51
|
+
* without materializing new on-disk copies for users who never installed them.
|
|
52
|
+
*/
|
|
53
|
+
refreshOnly?: boolean;
|
|
47
54
|
targetRoot?: string;
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -160,6 +167,15 @@ export async function installDefaultGjcDefinitions(
|
|
|
160
167
|
|
|
161
168
|
if (options.check) {
|
|
162
169
|
status = existing === undefined ? "missing" : existing === definition.content ? "matching" : "different";
|
|
170
|
+
} else if (options.refreshOnly) {
|
|
171
|
+
if (existing === undefined) {
|
|
172
|
+
status = "missing";
|
|
173
|
+
} else if (existing === definition.content) {
|
|
174
|
+
status = "matching";
|
|
175
|
+
} else {
|
|
176
|
+
await Bun.write(destination, definition.content);
|
|
177
|
+
status = "written";
|
|
178
|
+
}
|
|
163
179
|
} else if (existing !== undefined && !options.force) {
|
|
164
180
|
status = "skipped";
|
|
165
181
|
} else {
|
package/src/discovery/builtin.ts
CHANGED
|
@@ -165,9 +165,21 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
165
165
|
timeout = undefined;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
// Validate autoload: boolean only, warn on other types
|
|
169
|
+
let autoload: boolean | undefined;
|
|
170
|
+
if (serverConfig.autoload === undefined || serverConfig.autoload === null) {
|
|
171
|
+
autoload = undefined;
|
|
172
|
+
} else if (typeof serverConfig.autoload === "boolean") {
|
|
173
|
+
autoload = serverConfig.autoload;
|
|
174
|
+
} else {
|
|
175
|
+
logger.warn(`MCP server "${serverName}": invalid autoload type ${typeof serverConfig.autoload}, ignoring`);
|
|
176
|
+
autoload = undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
168
179
|
result.push({
|
|
169
180
|
name: serverName,
|
|
170
181
|
enabled,
|
|
182
|
+
autoload,
|
|
171
183
|
timeout,
|
|
172
184
|
command: serverConfig.command as string | undefined,
|
|
173
185
|
args: serverConfig.args as string[] | undefined,
|
package/src/discovery/cursor.ts
CHANGED
|
@@ -9,99 +9,28 @@
|
|
|
9
9
|
* - Project: .cursor/ (cwd only)
|
|
10
10
|
*
|
|
11
11
|
* Capabilities:
|
|
12
|
-
* - mcps: From mcp.json with mcpServers key
|
|
13
12
|
* - rules: From rules/*.mdc files with MDC frontmatter (description, globs, alwaysApply)
|
|
14
13
|
* - settings: From settings.json if present
|
|
14
|
+
*
|
|
15
|
+
* MCP servers are intentionally NOT inherited live from Cursor config: GJC owns
|
|
16
|
+
* MCP runtime execution. Use `gjc mcp import cursor` to copy definitions into
|
|
17
|
+
* GJC's own mcp.json instead.
|
|
15
18
|
*/
|
|
16
19
|
|
|
17
20
|
import { tryParseJson } from "@gajae-code/utils";
|
|
18
21
|
import { registerProvider } from "../capability";
|
|
19
22
|
import { readFile } from "../capability/fs";
|
|
20
|
-
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
21
23
|
import type { Rule } from "../capability/rule";
|
|
22
24
|
import { ruleCapability } from "../capability/rule";
|
|
23
25
|
import type { Settings } from "../capability/settings";
|
|
24
26
|
import { settingsCapability } from "../capability/settings";
|
|
25
27
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
|
|
26
|
-
import {
|
|
27
|
-
buildRuleFromMarkdown,
|
|
28
|
-
createSourceMeta,
|
|
29
|
-
expandEnvVarsDeep,
|
|
30
|
-
getProjectPath,
|
|
31
|
-
getUserPath,
|
|
32
|
-
loadFilesFromDir,
|
|
33
|
-
} from "./helpers";
|
|
28
|
+
import { buildRuleFromMarkdown, createSourceMeta, getProjectPath, getUserPath, loadFilesFromDir } from "./helpers";
|
|
34
29
|
|
|
35
30
|
const PROVIDER_ID = "cursor";
|
|
36
31
|
const DISPLAY_NAME = "Cursor";
|
|
37
32
|
const PRIORITY = 50;
|
|
38
33
|
|
|
39
|
-
// =============================================================================
|
|
40
|
-
// MCP Servers
|
|
41
|
-
// =============================================================================
|
|
42
|
-
|
|
43
|
-
function parseMCPServers(
|
|
44
|
-
content: string,
|
|
45
|
-
path: string,
|
|
46
|
-
level: "user" | "project",
|
|
47
|
-
): { items: MCPServer[]; warning?: string } {
|
|
48
|
-
const items: MCPServer[] = [];
|
|
49
|
-
|
|
50
|
-
const parsed = tryParseJson<{ mcpServers?: Record<string, unknown> }>(content);
|
|
51
|
-
if (!parsed?.mcpServers) {
|
|
52
|
-
return { items, warning: `${path}: missing or invalid 'mcpServers' key` };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const servers = expandEnvVarsDeep(parsed.mcpServers);
|
|
56
|
-
for (const [name, config] of Object.entries(servers)) {
|
|
57
|
-
const serverConfig = config as Record<string, unknown>;
|
|
58
|
-
items.push({
|
|
59
|
-
name,
|
|
60
|
-
command: serverConfig.command as string | undefined,
|
|
61
|
-
args: serverConfig.args as string[] | undefined,
|
|
62
|
-
env: serverConfig.env as Record<string, string> | undefined,
|
|
63
|
-
url: serverConfig.url as string | undefined,
|
|
64
|
-
headers: serverConfig.headers as Record<string, string> | undefined,
|
|
65
|
-
transport: ["stdio", "sse", "http"].includes(serverConfig.type as string)
|
|
66
|
-
? (serverConfig.type as "stdio" | "sse" | "http")
|
|
67
|
-
: undefined,
|
|
68
|
-
timeout: typeof serverConfig.timeout === "number" ? serverConfig.timeout : undefined,
|
|
69
|
-
_source: createSourceMeta(PROVIDER_ID, path, level),
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return { items };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
77
|
-
const items: MCPServer[] = [];
|
|
78
|
-
const warnings: string[] = [];
|
|
79
|
-
|
|
80
|
-
const userPath = getUserPath(ctx, "cursor", "mcp.json");
|
|
81
|
-
|
|
82
|
-
const [userContent, projectPath] = await Promise.all([
|
|
83
|
-
userPath ? readFile(userPath) : Promise.resolve(null),
|
|
84
|
-
getProjectPath(ctx, "cursor", "mcp.json"),
|
|
85
|
-
]);
|
|
86
|
-
|
|
87
|
-
const projectContentPromise = projectPath ? readFile(projectPath) : Promise.resolve(null);
|
|
88
|
-
|
|
89
|
-
if (userContent && userPath) {
|
|
90
|
-
const result = parseMCPServers(userContent, userPath, "user");
|
|
91
|
-
items.push(...result.items);
|
|
92
|
-
if (result.warning) warnings.push(result.warning);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const projectContent = await projectContentPromise;
|
|
96
|
-
if (projectContent && projectPath) {
|
|
97
|
-
const result = parseMCPServers(projectContent, projectPath, "project");
|
|
98
|
-
items.push(...result.items);
|
|
99
|
-
if (result.warning) warnings.push(result.warning);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return { items, warnings };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
34
|
// =============================================================================
|
|
106
35
|
// Rules
|
|
107
36
|
// =============================================================================
|
|
@@ -195,14 +124,6 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
|
|
|
195
124
|
// Provider Registration
|
|
196
125
|
// =============================================================================
|
|
197
126
|
|
|
198
|
-
registerProvider(mcpCapability.id, {
|
|
199
|
-
id: PROVIDER_ID,
|
|
200
|
-
displayName: DISPLAY_NAME,
|
|
201
|
-
description: "Load MCP servers from ~/.cursor/mcp.json and .cursor/mcp.json",
|
|
202
|
-
priority: PRIORITY,
|
|
203
|
-
load: loadMCPServers,
|
|
204
|
-
});
|
|
205
|
-
|
|
206
127
|
registerProvider(ruleCapability.id, {
|
|
207
128
|
id: PROVIDER_ID,
|
|
208
129
|
displayName: DISPLAY_NAME,
|
package/src/discovery/gemini.ts
CHANGED
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
* - Project: .gemini/ (cwd only)
|
|
10
10
|
*
|
|
11
11
|
* Capabilities:
|
|
12
|
-
* - mcps: From settings.json with mcpServers key
|
|
13
12
|
* - context-files: GEMINI.md files
|
|
14
13
|
* - system-prompt: system.md files for custom system prompt
|
|
15
14
|
* - extensions: From extensions/STAR/gemini-extension.json manifests (STAR = wildcard)
|
|
16
15
|
* - settings: From settings.json
|
|
16
|
+
*
|
|
17
|
+
* MCP servers are intentionally NOT inherited live from Gemini config: GJC owns
|
|
18
|
+
* MCP runtime execution. Copy definitions into GJC's own mcp.json instead.
|
|
17
19
|
*/
|
|
18
20
|
import * as path from "node:path";
|
|
19
21
|
import { tryParseJson } from "@gajae-code/utils";
|
|
@@ -22,7 +24,6 @@ import { type ContextFile, contextFileCapability } from "../capability/context-f
|
|
|
22
24
|
import { type Extension, type ExtensionManifest, extensionCapability } from "../capability/extension";
|
|
23
25
|
import { type ExtensionModule, extensionModuleCapability } from "../capability/extension-module";
|
|
24
26
|
import { readDirEntries, readFile } from "../capability/fs";
|
|
25
|
-
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
26
27
|
import { type Settings, settingsCapability } from "../capability/settings";
|
|
27
28
|
import { type SystemPrompt, systemPromptCapability } from "../capability/system-prompt";
|
|
28
29
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
@@ -31,7 +32,6 @@ import {
|
|
|
31
32
|
calculateDepth,
|
|
32
33
|
createSourceMeta,
|
|
33
34
|
discoverExtensionModulePaths,
|
|
34
|
-
expandEnvVarsDeep,
|
|
35
35
|
getProjectPath,
|
|
36
36
|
getUserPath,
|
|
37
37
|
} from "./helpers";
|
|
@@ -40,84 +40,6 @@ const PROVIDER_ID = "gemini";
|
|
|
40
40
|
const DISPLAY_NAME = "Gemini CLI";
|
|
41
41
|
const PRIORITY = 60;
|
|
42
42
|
|
|
43
|
-
// =============================================================================
|
|
44
|
-
// MCP Servers
|
|
45
|
-
// =============================================================================
|
|
46
|
-
|
|
47
|
-
async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
48
|
-
const items: MCPServer[] = [];
|
|
49
|
-
const warnings: string[] = [];
|
|
50
|
-
|
|
51
|
-
// User-level: ~/.gemini/settings.json → mcpServers
|
|
52
|
-
const userPath = getUserPath(ctx, "gemini", "settings.json");
|
|
53
|
-
if (userPath) {
|
|
54
|
-
const result = await loadMCPFromSettings(ctx, userPath, "user");
|
|
55
|
-
items.push(...result.items);
|
|
56
|
-
if (result.warnings) warnings.push(...result.warnings);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Project-level: .gemini/settings.json → mcpServers
|
|
60
|
-
const projectPath = getProjectPath(ctx, "gemini", "settings.json");
|
|
61
|
-
if (projectPath) {
|
|
62
|
-
const result = await loadMCPFromSettings(ctx, projectPath, "project");
|
|
63
|
-
items.push(...result.items);
|
|
64
|
-
if (result.warnings) warnings.push(...result.warnings);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { items, warnings };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function loadMCPFromSettings(
|
|
71
|
-
_ctx: LoadContext,
|
|
72
|
-
path: string,
|
|
73
|
-
level: "user" | "project",
|
|
74
|
-
): Promise<LoadResult<MCPServer>> {
|
|
75
|
-
const items: MCPServer[] = [];
|
|
76
|
-
const warnings: string[] = [];
|
|
77
|
-
|
|
78
|
-
const content = await readFile(path);
|
|
79
|
-
if (!content) {
|
|
80
|
-
return { items, warnings };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const parsed = tryParseJson<{ mcpServers?: Record<string, unknown> }>(content);
|
|
84
|
-
if (!parsed) {
|
|
85
|
-
warnings.push(`Invalid JSON in ${path}`);
|
|
86
|
-
return { items, warnings };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!parsed.mcpServers || typeof parsed.mcpServers !== "object") {
|
|
90
|
-
return { items, warnings };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const servers = expandEnvVarsDeep(parsed.mcpServers);
|
|
94
|
-
|
|
95
|
-
for (const [name, config] of Object.entries(servers)) {
|
|
96
|
-
if (!config || typeof config !== "object") {
|
|
97
|
-
warnings.push(`Invalid config for server "${name}" in ${path}`);
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const raw = config as Record<string, unknown>;
|
|
102
|
-
|
|
103
|
-
items.push({
|
|
104
|
-
name,
|
|
105
|
-
command: typeof raw.command === "string" ? raw.command : undefined,
|
|
106
|
-
args: Array.isArray(raw.args) ? (raw.args as string[]) : undefined,
|
|
107
|
-
env: raw.env && typeof raw.env === "object" ? (raw.env as Record<string, string>) : undefined,
|
|
108
|
-
url: typeof raw.url === "string" ? raw.url : undefined,
|
|
109
|
-
headers: raw.headers && typeof raw.headers === "object" ? (raw.headers as Record<string, string>) : undefined,
|
|
110
|
-
transport: ["stdio", "sse", "http"].includes(raw.type as string)
|
|
111
|
-
? (raw.type as "stdio" | "sse" | "http")
|
|
112
|
-
: undefined,
|
|
113
|
-
timeout: typeof raw.timeout === "number" ? raw.timeout : undefined,
|
|
114
|
-
_source: createSourceMeta(PROVIDER_ID, path, level),
|
|
115
|
-
} as MCPServer);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return { items, warnings };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
43
|
// =============================================================================
|
|
122
44
|
// Context Files
|
|
123
45
|
// =============================================================================
|
|
@@ -296,14 +218,6 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
|
|
|
296
218
|
// Provider Registration
|
|
297
219
|
// =============================================================================
|
|
298
220
|
|
|
299
|
-
registerProvider(mcpCapability.id, {
|
|
300
|
-
id: PROVIDER_ID,
|
|
301
|
-
displayName: DISPLAY_NAME,
|
|
302
|
-
description: "Load MCP servers from ~/.gemini/settings.json and .gemini/settings.json",
|
|
303
|
-
priority: PRIORITY,
|
|
304
|
-
load: loadMCPServers,
|
|
305
|
-
});
|
|
306
|
-
|
|
307
221
|
registerProvider(contextFileCapability.id, {
|
|
308
222
|
id: PROVIDER_ID,
|
|
309
223
|
displayName: DISPLAY_NAME,
|
package/src/discovery/index.ts
CHANGED
|
@@ -30,7 +30,10 @@ import "./opencode";
|
|
|
30
30
|
import "./github";
|
|
31
31
|
import "./mcp-json";
|
|
32
32
|
import "./ssh";
|
|
33
|
-
|
|
33
|
+
// NOTE: There is deliberately no VS Code provider and no MCP registration in
|
|
34
|
+
// the cursor/gemini/opencode/windsurf providers: GJC does not inherit MCP
|
|
35
|
+
// servers live from other hosts. MCP comes from GJC's own config (builtin,
|
|
36
|
+
// mcp-json), validated plugin bundles, or an explicit `gjc mcp import <host>`.
|
|
34
37
|
import "./windsurf";
|
|
35
38
|
|
|
36
39
|
// Re-export the main API from capability registry
|
|
@@ -25,6 +25,7 @@ interface MCPConfigFile {
|
|
|
25
25
|
string,
|
|
26
26
|
{
|
|
27
27
|
enabled?: boolean;
|
|
28
|
+
autoload?: boolean;
|
|
28
29
|
timeout?: number;
|
|
29
30
|
command?: string;
|
|
30
31
|
args?: string[];
|
|
@@ -82,9 +83,19 @@ function transformMCPConfig(config: MCPConfigFile, source: SourceMeta): MCPServe
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
let autoload: boolean | undefined;
|
|
87
|
+
if (serverConfig.autoload !== undefined) {
|
|
88
|
+
if (typeof serverConfig.autoload === "boolean") {
|
|
89
|
+
autoload = serverConfig.autoload;
|
|
90
|
+
} else {
|
|
91
|
+
logger.warn("MCP server has invalid 'autoload' value, ignoring", { name, value: serverConfig.autoload });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
85
95
|
const server: MCPServer = {
|
|
86
96
|
name,
|
|
87
97
|
enabled,
|
|
98
|
+
autoload,
|
|
88
99
|
timeout,
|
|
89
100
|
command: serverConfig.command,
|
|
90
101
|
args: serverConfig.args,
|
|
@@ -7,21 +7,23 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Capabilities:
|
|
9
9
|
* - context-files: AGENTS.md (user-level only at ~/.config/opencode/AGENTS.md)
|
|
10
|
-
* - mcps: From opencode.json "mcp" key
|
|
11
10
|
* - settings: From opencode.json
|
|
12
11
|
* - skills: From skills/ subdirectories
|
|
13
12
|
* - slash-commands: From commands/ subdirectories
|
|
14
13
|
* - extension-modules: From plugins/ subdirectories
|
|
15
14
|
*
|
|
15
|
+
* MCP servers are intentionally NOT inherited live from OpenCode config: GJC
|
|
16
|
+
* owns MCP runtime execution. Use `gjc mcp import opencode` to copy definitions
|
|
17
|
+
* into GJC's own mcp.json instead.
|
|
18
|
+
*
|
|
16
19
|
* Priority: 55 (tool-specific provider)
|
|
17
20
|
*/
|
|
18
21
|
import * as path from "node:path";
|
|
19
|
-
import {
|
|
22
|
+
import { parseFrontmatter, tryParseJson } from "@gajae-code/utils";
|
|
20
23
|
import { registerProvider } from "../capability";
|
|
21
24
|
import { type ContextFile, contextFileCapability } from "../capability/context-file";
|
|
22
25
|
import { type ExtensionModule, extensionModuleCapability } from "../capability/extension-module";
|
|
23
26
|
import { readFile } from "../capability/fs";
|
|
24
|
-
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
25
27
|
import { type Settings, settingsCapability } from "../capability/settings";
|
|
26
28
|
import { type Skill, skillCapability } from "../capability/skill";
|
|
27
29
|
import { type SlashCommand, slashCommandCapability } from "../capability/slash-command";
|
|
@@ -32,7 +34,6 @@ import {
|
|
|
32
34
|
buildExtensionModuleItems,
|
|
33
35
|
createSourceMeta,
|
|
34
36
|
discoverExtensionModulePaths,
|
|
35
|
-
expandEnvVarsDeep,
|
|
36
37
|
getProjectPath,
|
|
37
38
|
getUserPath,
|
|
38
39
|
loadFilesFromDir,
|
|
@@ -43,22 +44,6 @@ const PROVIDER_ID = "opencode";
|
|
|
43
44
|
const DISPLAY_NAME = "OpenCode";
|
|
44
45
|
const PRIORITY = 55;
|
|
45
46
|
|
|
46
|
-
// =============================================================================
|
|
47
|
-
// JSON Config Loading
|
|
48
|
-
// =============================================================================
|
|
49
|
-
|
|
50
|
-
async function loadJsonConfig(configPath: string): Promise<Record<string, unknown> | null> {
|
|
51
|
-
const content = await readFile(configPath);
|
|
52
|
-
if (!content) return null;
|
|
53
|
-
|
|
54
|
-
const parsed = tryParseJson<Record<string, unknown>>(content);
|
|
55
|
-
if (!parsed) {
|
|
56
|
-
logger.warn("Failed to parse OpenCode JSON config", { path: configPath });
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
return parsed;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
47
|
// =============================================================================
|
|
63
48
|
// Context Files (AGENTS.md)
|
|
64
49
|
// =============================================================================
|
|
@@ -84,100 +69,6 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
|
|
|
84
69
|
return { items, warnings };
|
|
85
70
|
}
|
|
86
71
|
|
|
87
|
-
// =============================================================================
|
|
88
|
-
// MCP Servers (opencode.json → mcp)
|
|
89
|
-
// =============================================================================
|
|
90
|
-
|
|
91
|
-
/** OpenCode MCP server config (from opencode.json "mcp" key) */
|
|
92
|
-
interface OpenCodeMCPConfig {
|
|
93
|
-
type?: "local" | "remote";
|
|
94
|
-
command?: string;
|
|
95
|
-
args?: string[];
|
|
96
|
-
env?: Record<string, string>;
|
|
97
|
-
url?: string;
|
|
98
|
-
headers?: Record<string, string>;
|
|
99
|
-
enabled?: boolean;
|
|
100
|
-
timeout?: number;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
104
|
-
const items: MCPServer[] = [];
|
|
105
|
-
const warnings: string[] = [];
|
|
106
|
-
|
|
107
|
-
// User-level: ~/.config/opencode/opencode.json
|
|
108
|
-
const userConfigPath = getUserPath(ctx, "opencode", "opencode.json");
|
|
109
|
-
if (userConfigPath) {
|
|
110
|
-
const config = await loadJsonConfig(userConfigPath);
|
|
111
|
-
if (config) {
|
|
112
|
-
const result = extractMCPServers(config, userConfigPath, "user");
|
|
113
|
-
items.push(...result.items);
|
|
114
|
-
if (result.warnings) warnings.push(...result.warnings);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Project-level: opencode.json in project root
|
|
119
|
-
const projectConfigPath = path.join(ctx.cwd, "opencode.json");
|
|
120
|
-
const projectConfig = await loadJsonConfig(projectConfigPath);
|
|
121
|
-
if (projectConfig) {
|
|
122
|
-
const result = extractMCPServers(projectConfig, projectConfigPath, "project");
|
|
123
|
-
items.push(...result.items);
|
|
124
|
-
if (result.warnings) warnings.push(...result.warnings);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return { items, warnings };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function extractMCPServers(
|
|
131
|
-
config: Record<string, unknown>,
|
|
132
|
-
configPath: string,
|
|
133
|
-
level: "user" | "project",
|
|
134
|
-
): LoadResult<MCPServer> {
|
|
135
|
-
const items: MCPServer[] = [];
|
|
136
|
-
const warnings: string[] = [];
|
|
137
|
-
|
|
138
|
-
if (!config.mcp || typeof config.mcp !== "object") {
|
|
139
|
-
return { items, warnings };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const servers = expandEnvVarsDeep(config.mcp as Record<string, unknown>);
|
|
143
|
-
|
|
144
|
-
for (const [name, raw] of Object.entries(servers)) {
|
|
145
|
-
if (!raw || typeof raw !== "object") {
|
|
146
|
-
warnings.push(`Invalid MCP config for "${name}" in ${configPath}`);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const serverConfig = raw as OpenCodeMCPConfig;
|
|
151
|
-
|
|
152
|
-
// Determine transport from OpenCode's "type" field
|
|
153
|
-
let transport: "stdio" | "sse" | "http" | undefined;
|
|
154
|
-
if (serverConfig.type === "local") {
|
|
155
|
-
transport = "stdio";
|
|
156
|
-
} else if (serverConfig.type === "remote") {
|
|
157
|
-
transport = "http";
|
|
158
|
-
} else if (serverConfig.url) {
|
|
159
|
-
transport = "http";
|
|
160
|
-
} else if (serverConfig.command) {
|
|
161
|
-
transport = "stdio";
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
items.push({
|
|
165
|
-
name,
|
|
166
|
-
command: serverConfig.command,
|
|
167
|
-
args: Array.isArray(serverConfig.args) ? (serverConfig.args as string[]) : undefined,
|
|
168
|
-
env: serverConfig.env && typeof serverConfig.env === "object" ? serverConfig.env : undefined,
|
|
169
|
-
url: typeof serverConfig.url === "string" ? serverConfig.url : undefined,
|
|
170
|
-
headers: serverConfig.headers && typeof serverConfig.headers === "object" ? serverConfig.headers : undefined,
|
|
171
|
-
enabled: serverConfig.enabled,
|
|
172
|
-
timeout: typeof serverConfig.timeout === "number" ? serverConfig.timeout : undefined,
|
|
173
|
-
transport,
|
|
174
|
-
_source: createSourceMeta(PROVIDER_ID, configPath, level),
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return { items, warnings };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
72
|
// =============================================================================
|
|
182
73
|
// Skills (skills/)
|
|
183
74
|
// =============================================================================
|
|
@@ -357,14 +248,6 @@ registerProvider(contextFileCapability.id, {
|
|
|
357
248
|
load: loadContextFiles,
|
|
358
249
|
});
|
|
359
250
|
|
|
360
|
-
registerProvider(mcpCapability.id, {
|
|
361
|
-
id: PROVIDER_ID,
|
|
362
|
-
displayName: DISPLAY_NAME,
|
|
363
|
-
description: "Load MCP servers from opencode.json mcp key",
|
|
364
|
-
priority: PRIORITY,
|
|
365
|
-
load: loadMCPServers,
|
|
366
|
-
});
|
|
367
|
-
|
|
368
251
|
registerProvider(skillCapability.id, {
|
|
369
252
|
id: PROVIDER_ID,
|
|
370
253
|
displayName: DISPLAY_NAME,
|