@sayknow-cli/coding-agent 0.3.10 → 0.3.12
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 +0 -13
- package/dist/types/build-metadata.d.ts +7 -0
- package/dist/types/capability/mcp.d.ts +3 -1
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/modes/acp/acp-event-mapper.d.ts +2 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +6 -0
- package/dist/types/modes/components/status-line.d.ts +1 -0
- package/dist/types/modes/components/welcome.d.ts +1 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -2
- package/dist/types/modes/utils/ui-helpers.d.ts +12 -0
- package/dist/types/notifications/telegram-daemon.d.ts +2 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +4 -3
- package/dist/types/runtime-mcp/types.d.ts +4 -3
- package/dist/types/session/agent-session.d.ts +16 -0
- package/dist/types/session/session-manager.d.ts +1 -0
- package/dist/types/tools/skill.d.ts +9 -8
- package/dist/types/utils/linkedom.d.ts +4 -0
- package/dist/types/utils/pasted-image-path.d.ts +5 -3
- package/package.json +7 -7
- package/scripts/build-binary.ts +2 -43
- package/scripts/compile-args.ts +106 -0
- package/scripts/generate-docs-index.ts +1 -0
- package/src/build-metadata.ts +104 -0
- package/src/capability/mcp.ts +3 -1
- package/src/cli/mcp-cli.ts +108 -26
- package/src/cli.ts +21 -0
- package/src/commands/mcp.ts +8 -8
- package/src/commands/stats.ts +6 -2
- package/src/config/keybindings.ts +2 -2
- package/src/config/mcp-schema.json +21 -17
- package/src/config/model-profiles.ts +23 -23
- package/src/discovery/builtin.ts +14 -0
- package/src/discovery/mcp-json.ts +14 -0
- package/src/eval/js/executor.ts +7 -1
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/skc-protocol.ts +14 -1
- package/src/modes/acp/acp-agent.ts +72 -16
- package/src/modes/acp/acp-client-bridge.ts +27 -5
- package/src/modes/acp/acp-event-mapper.ts +39 -1
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/hook-selector.ts +4 -0
- package/src/modes/components/model-selector.ts +17 -6
- package/src/modes/components/session-selector.ts +2 -2
- package/src/modes/components/status-line/presets.ts +5 -19
- package/src/modes/components/status-line/segments.ts +14 -0
- package/src/modes/components/status-line/types.ts +6 -0
- package/src/modes/components/status-line.ts +13 -6
- package/src/modes/components/tool-execution.ts +1 -1
- package/src/modes/components/welcome.ts +4 -1
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +9 -9
- package/src/modes/controllers/input-controller.ts +8 -2
- package/src/modes/controllers/selector-controller.ts +7 -3
- package/src/modes/interactive-mode.ts +12 -4
- package/src/modes/rpc/rpc-client.ts +30 -6
- package/src/modes/utils/ui-helpers.ts +154 -32
- package/src/notifications/telegram-daemon.ts +28 -2
- package/src/prompts/tools/skill.md +2 -2
- package/src/runtime-mcp/config-writer.ts +4 -3
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/types.ts +4 -3
- package/src/session/agent-session.ts +117 -3
- package/src/session/session-manager.ts +68 -40
- package/src/skc-runtime/state-runtime.ts +105 -12
- package/src/skc-runtime/workflow-manifest.generated.json +4 -28
- package/src/skc-runtime/workflow-manifest.ts +1 -7
- package/src/slash-commands/builtin-registry.ts +9 -4
- package/src/tools/bash-interactive.ts +9 -4
- package/src/tools/browser/readable.ts +2 -2
- package/src/tools/fetch.ts +5 -5
- package/src/tools/skill.ts +14 -11
- package/src/utils/linkedom.ts +14 -0
- package/src/utils/pasted-image-path.ts +23 -9
- package/src/web/scrapers/arxiv.ts +2 -2
- package/src/web/scrapers/go-pkg.ts +2 -2
- package/src/web/scrapers/iacr.ts +2 -2
- package/src/web/scrapers/readthedocs.ts +2 -2
- package/src/web/scrapers/twitter.ts +3 -2
- package/src/web/scrapers/wikipedia.ts +2 -2
package/src/cli/mcp-cli.ts
CHANGED
|
@@ -37,14 +37,27 @@ interface ScopedPath {
|
|
|
37
37
|
path: string;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
interface RuntimeDisclosure {
|
|
41
|
+
runtimeStatus: "storage-only";
|
|
42
|
+
runtimeLoadedByStandalone: false;
|
|
43
|
+
runtimeNote: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
interface RedactedServerEntry {
|
|
41
47
|
name: string;
|
|
42
48
|
config: MCPServerConfig;
|
|
43
49
|
}
|
|
44
50
|
|
|
51
|
+
interface RuntimeRedactedServerEntry extends RedactedServerEntry, RuntimeDisclosure {}
|
|
52
|
+
|
|
45
53
|
const REDACTED = "<redacted>";
|
|
46
54
|
const SENSITIVE_KEY_PATTERN =
|
|
47
55
|
/(?:token|secret|key|credential|password|passwd|pwd|authorization|auth|bearer|cookie|session)/i;
|
|
56
|
+
const STORAGE_ONLY_RUNTIME_DISCLOSURE: RuntimeDisclosure = {
|
|
57
|
+
runtimeStatus: "storage-only",
|
|
58
|
+
runtimeLoadedByStandalone: false,
|
|
59
|
+
runtimeNote: "Stored MCP registrations are not loaded by normal standalone skc sessions today.",
|
|
60
|
+
};
|
|
48
61
|
|
|
49
62
|
function resolvePath(args: MCPCommandArgs): ScopedPath {
|
|
50
63
|
const scope = args.flags.project ? "project" : "user";
|
|
@@ -128,6 +141,50 @@ function redactRecord(
|
|
|
128
141
|
);
|
|
129
142
|
}
|
|
130
143
|
|
|
144
|
+
function redactUrl(value: string | undefined): string | undefined {
|
|
145
|
+
if (!value) return value;
|
|
146
|
+
try {
|
|
147
|
+
const url = new URL(value);
|
|
148
|
+
if (url.username) url.username = REDACTED;
|
|
149
|
+
if (url.password) url.password = REDACTED;
|
|
150
|
+
if (url.search) {
|
|
151
|
+
for (const key of Array.from(url.searchParams.keys())) {
|
|
152
|
+
url.searchParams.set(key, REDACTED);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
url.hash = "";
|
|
156
|
+
return url.toString();
|
|
157
|
+
} catch {
|
|
158
|
+
return SENSITIVE_KEY_PATTERN.test(value) ? REDACTED : value;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function redactArgs(args: string[] | undefined): string[] | undefined {
|
|
163
|
+
if (!args) return undefined;
|
|
164
|
+
const redacted: string[] = [];
|
|
165
|
+
let redactNext = false;
|
|
166
|
+
for (const arg of args) {
|
|
167
|
+
if (redactNext) {
|
|
168
|
+
redacted.push(REDACTED);
|
|
169
|
+
redactNext = false;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const equalsIndex = arg.indexOf("=");
|
|
173
|
+
if (equalsIndex > 0) {
|
|
174
|
+
const key = arg.slice(0, equalsIndex);
|
|
175
|
+
redacted.push(SENSITIVE_KEY_PATTERN.test(key) ? `${key}=${REDACTED}` : arg);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (arg.startsWith("-") && SENSITIVE_KEY_PATTERN.test(arg)) {
|
|
179
|
+
redacted.push(arg);
|
|
180
|
+
redactNext = true;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
redacted.push(SENSITIVE_KEY_PATTERN.test(arg) ? REDACTED : arg);
|
|
184
|
+
}
|
|
185
|
+
return redacted;
|
|
186
|
+
}
|
|
187
|
+
|
|
131
188
|
export function redactMCPServerConfig(config: MCPServerConfig): MCPServerConfig {
|
|
132
189
|
const redacted = { ...config } as MCPServerConfig;
|
|
133
190
|
if ("env" in redacted) {
|
|
@@ -138,11 +195,19 @@ export function redactMCPServerConfig(config: MCPServerConfig): MCPServerConfig
|
|
|
138
195
|
const headers = redactRecord(redacted.headers, true);
|
|
139
196
|
if (headers) redacted.headers = headers;
|
|
140
197
|
}
|
|
198
|
+
if ("url" in redacted) {
|
|
199
|
+
const url = redactUrl(redacted.url);
|
|
200
|
+
if (url) redacted.url = url;
|
|
201
|
+
}
|
|
202
|
+
if ("args" in redacted) {
|
|
203
|
+
const args = redactArgs(redacted.args);
|
|
204
|
+
if (args) redacted.args = args;
|
|
205
|
+
}
|
|
141
206
|
if (redacted.auth) {
|
|
142
207
|
redacted.auth = {
|
|
143
208
|
type: redacted.auth.type,
|
|
144
209
|
credentialId: redacted.auth.credentialId ? REDACTED : undefined,
|
|
145
|
-
tokenUrl: redacted.auth.tokenUrl,
|
|
210
|
+
tokenUrl: redactUrl(redacted.auth.tokenUrl),
|
|
146
211
|
clientId: redacted.auth.clientId ? REDACTED : undefined,
|
|
147
212
|
clientSecret: redacted.auth.clientSecret ? REDACTED : undefined,
|
|
148
213
|
};
|
|
@@ -151,7 +216,7 @@ export function redactMCPServerConfig(config: MCPServerConfig): MCPServerConfig
|
|
|
151
216
|
redacted.oauth = {
|
|
152
217
|
clientId: redacted.oauth.clientId ? REDACTED : undefined,
|
|
153
218
|
clientSecret: redacted.oauth.clientSecret ? REDACTED : undefined,
|
|
154
|
-
redirectUri: redacted.oauth.redirectUri,
|
|
219
|
+
redirectUri: redactUrl(redacted.oauth.redirectUri),
|
|
155
220
|
callbackPort: redacted.oauth.callbackPort,
|
|
156
221
|
callbackPath: redacted.oauth.callbackPath,
|
|
157
222
|
};
|
|
@@ -159,10 +224,14 @@ export function redactMCPServerConfig(config: MCPServerConfig): MCPServerConfig
|
|
|
159
224
|
return redacted;
|
|
160
225
|
}
|
|
161
226
|
|
|
162
|
-
function
|
|
227
|
+
function withRuntimeDisclosure<T extends object>(value: T): T & RuntimeDisclosure {
|
|
228
|
+
return { ...value, ...STORAGE_ONLY_RUNTIME_DISCLOSURE };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function collectEntries(config: MCPConfigFile): RuntimeRedactedServerEntry[] {
|
|
163
232
|
return Object.entries(config.mcpServers ?? {})
|
|
164
233
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
165
|
-
.map(([name, serverConfig]) => ({ name, config: redactMCPServerConfig(serverConfig) }));
|
|
234
|
+
.map(([name, serverConfig]) => withRuntimeDisclosure({ name, config: redactMCPServerConfig(serverConfig) }));
|
|
166
235
|
}
|
|
167
236
|
|
|
168
237
|
function writeJson(value: unknown): void {
|
|
@@ -188,37 +257,46 @@ async function runAdd(args: MCPCommandArgs, scoped: ScopedPath): Promise<void> {
|
|
|
188
257
|
const result = await upsertMCPServer(scoped.path, args.name, config, { force: args.flags.force });
|
|
189
258
|
const redacted = redactMCPServerConfig(config);
|
|
190
259
|
if (args.flags.json) {
|
|
191
|
-
writeJson(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
260
|
+
writeJson(
|
|
261
|
+
withRuntimeDisclosure({
|
|
262
|
+
action: "add",
|
|
263
|
+
status: result.status,
|
|
264
|
+
name: args.name,
|
|
265
|
+
scope: scoped.scope,
|
|
266
|
+
path: scoped.path,
|
|
267
|
+
config: redacted,
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
199
270
|
return;
|
|
200
271
|
}
|
|
201
272
|
if (result.status === "skipped") {
|
|
202
273
|
process.stdout.write(
|
|
203
|
-
`MCP server "${args.name}" already exists in ${scoped.scope} config. Pass --force to overwrite
|
|
274
|
+
`MCP server "${args.name}" already exists in ${scoped.scope} config. Pass --force to overwrite. ` +
|
|
275
|
+
"Status: storage-only; normal standalone skc sessions do not load stored MCP registrations today.\n",
|
|
204
276
|
);
|
|
205
277
|
return;
|
|
206
278
|
}
|
|
207
|
-
process.stdout.write(
|
|
279
|
+
process.stdout.write(
|
|
280
|
+
`MCP server "${args.name}" ${result.status} in ${scoped.scope} config: ${scoped.path}\nStatus: storage-only; normal standalone skc sessions do not load stored MCP registrations today.\n`,
|
|
281
|
+
);
|
|
208
282
|
}
|
|
209
283
|
|
|
210
284
|
async function runList(args: MCPCommandArgs, scoped: ScopedPath): Promise<void> {
|
|
211
285
|
const config = await readMCPConfigFile(scoped.path);
|
|
212
286
|
const entries = collectEntries(config);
|
|
213
287
|
if (args.flags.json) {
|
|
214
|
-
writeJson({ action: "list", scope: scoped.scope, path: scoped.path, servers: entries });
|
|
288
|
+
writeJson(withRuntimeDisclosure({ action: "list", scope: scoped.scope, path: scoped.path, servers: entries }));
|
|
215
289
|
return;
|
|
216
290
|
}
|
|
217
291
|
if (entries.length === 0) {
|
|
218
|
-
process.stdout.write(
|
|
292
|
+
process.stdout.write(
|
|
293
|
+
`No MCP servers registered in ${scoped.scope} config: ${scoped.path}\nStatus: storage-only; normal standalone skc sessions do not load stored MCP registrations today.\n`,
|
|
294
|
+
);
|
|
219
295
|
return;
|
|
220
296
|
}
|
|
221
|
-
process.stdout.write(
|
|
297
|
+
process.stdout.write(
|
|
298
|
+
`MCP servers in ${scoped.scope} config: ${scoped.path}\nStatus: storage-only; normal standalone skc sessions do not load stored MCP registrations today.\n`,
|
|
299
|
+
);
|
|
222
300
|
for (const entry of entries) {
|
|
223
301
|
process.stdout.write(`${renderDetails(entry)}\n`);
|
|
224
302
|
}
|
|
@@ -233,17 +311,21 @@ async function runRemove(args: MCPCommandArgs, scoped: ScopedPath): Promise<void
|
|
|
233
311
|
await removeMCPServer(scoped.path, args.name);
|
|
234
312
|
const entry = { name: args.name, config: redactMCPServerConfig(existing) };
|
|
235
313
|
if (args.flags.json) {
|
|
236
|
-
writeJson(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
314
|
+
writeJson(
|
|
315
|
+
withRuntimeDisclosure({
|
|
316
|
+
action: "remove",
|
|
317
|
+
status: "removed",
|
|
318
|
+
name: args.name,
|
|
319
|
+
scope: scoped.scope,
|
|
320
|
+
path: scoped.path,
|
|
321
|
+
removed: entry,
|
|
322
|
+
}),
|
|
323
|
+
);
|
|
244
324
|
return;
|
|
245
325
|
}
|
|
246
|
-
process.stdout.write(
|
|
326
|
+
process.stdout.write(
|
|
327
|
+
`Removed MCP server "${args.name}" from ${scoped.scope} config: ${scoped.path}\nStatus: storage-only; normal standalone skc sessions do not load stored MCP registrations today.\n`,
|
|
328
|
+
);
|
|
247
329
|
process.stdout.write(`${renderDetails(entry)}\n`);
|
|
248
330
|
}
|
|
249
331
|
|
package/src/cli.ts
CHANGED
|
@@ -87,6 +87,23 @@ async function installRuntimeGlobals(): Promise<void> {
|
|
|
87
87
|
delete process.env.MallocStackLoggingNoCompact;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function isStatsHelpFastPath(argv: string[]): boolean {
|
|
91
|
+
return argv[0] === "stats" && (argv.includes("--help") || argv.includes("-h"));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function showStatsFastHelp(): void {
|
|
95
|
+
process.stdout.write(`Usage: ${APP_NAME} stats [options]
|
|
96
|
+
|
|
97
|
+
View usage statistics
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
-p, --port <number> Port for the dashboard server (default: 3847)
|
|
101
|
+
-j, --json Output stats as JSON
|
|
102
|
+
-s, --summary Print summary to console
|
|
103
|
+
-h, --help Show this help
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
|
|
90
107
|
function isNotifyDaemonInternalFastPath(argv: string[]): boolean {
|
|
91
108
|
return argv[0] === "notify" && argv[1] === "daemon-internal";
|
|
92
109
|
}
|
|
@@ -264,6 +281,10 @@ export async function runCli(argv: string[]): Promise<void> {
|
|
|
264
281
|
process.exitCode = await runFixtureReport(id);
|
|
265
282
|
return;
|
|
266
283
|
}
|
|
284
|
+
if (isStatsHelpFastPath(argv)) {
|
|
285
|
+
showStatsFastHelp();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
267
288
|
if (hasRootHelpFlag(argv)) {
|
|
268
289
|
const { renderRootHelp } = await import("@sayknow-cli/utils/cli");
|
|
269
290
|
const { getExtraHelpText } = await import("./cli/fast-help");
|
package/src/commands/mcp.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Explicit MCP server config storage for standalone SKC.
|
|
3
3
|
*/
|
|
4
4
|
import { Args, Command, Flags } from "@sayknow-cli/utils/cli";
|
|
5
5
|
import { type MCPAction, type MCPCommandArgs, runMCPCommand } from "../cli/mcp-cli";
|
|
@@ -7,7 +7,7 @@ import { type MCPAction, type MCPCommandArgs, runMCPCommand } from "../cli/mcp-c
|
|
|
7
7
|
const ACTIONS: MCPAction[] = ["add", "list", "remove"];
|
|
8
8
|
|
|
9
9
|
export default class MCP extends Command {
|
|
10
|
-
static description = "
|
|
10
|
+
static description = "Store standalone MCP server definitions without loading them at runtime";
|
|
11
11
|
static delegateHelp = true;
|
|
12
12
|
|
|
13
13
|
static examples = [
|
|
@@ -81,15 +81,15 @@ export default class MCP extends Command {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
private printHelp(): void {
|
|
84
|
-
process.stdout.write(`
|
|
84
|
+
process.stdout.write(`Store standalone MCP server definitions in SKC config without loading them at runtime
|
|
85
85
|
|
|
86
86
|
USAGE
|
|
87
87
|
$ skc mcp [add|list|remove] [NAME] [COMMAND_OR_URL] [ARGS...] [FLAGS]
|
|
88
88
|
|
|
89
89
|
COMMANDS
|
|
90
|
-
add
|
|
91
|
-
list List
|
|
92
|
-
remove Remove a
|
|
90
|
+
add Store an explicit user-provided MCP server definition
|
|
91
|
+
list List stored servers with env/header/auth values redacted
|
|
92
|
+
remove Remove a stored server and print the removed definition redacted
|
|
93
93
|
|
|
94
94
|
FLAGS
|
|
95
95
|
--project Use project scope (./.skc/mcp.json) instead of user scope
|
|
@@ -110,8 +110,8 @@ EXAMPLES
|
|
|
110
110
|
$ skc mcp list --json
|
|
111
111
|
$ skc mcp remove context7
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
This command
|
|
113
|
+
STORAGE/RUNTIME
|
|
114
|
+
This command stores only the server definition supplied on this invocation. It does not import or inherit Claude Code, Codex, OpenCode, or other live MCP configs. Normal standalone skc sessions do not load stored MCP registrations today. Public output redacts env, header, auth, and OAuth credential values.
|
|
115
115
|
`);
|
|
116
116
|
}
|
|
117
117
|
}
|
package/src/commands/stats.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* View usage statistics dashboard.
|
|
3
3
|
*/
|
|
4
4
|
import { Command, Flags } from "@sayknow-cli/utils/cli";
|
|
5
|
-
import {
|
|
6
|
-
import { initTheme } from "../modes/theme/theme";
|
|
5
|
+
import type { StatsCommandArgs } from "../cli/stats-cli";
|
|
7
6
|
|
|
8
7
|
export default class Stats extends Command {
|
|
9
8
|
static description = "View usage statistics";
|
|
@@ -23,6 +22,11 @@ export default class Stats extends Command {
|
|
|
23
22
|
summary: flags.summary,
|
|
24
23
|
};
|
|
25
24
|
|
|
25
|
+
const [{ initTheme }, { runStatsCommand }] = await Promise.all([
|
|
26
|
+
import("../modes/theme/theme"),
|
|
27
|
+
import("../cli/stats-cli"),
|
|
28
|
+
]);
|
|
29
|
+
|
|
26
30
|
await initTheme();
|
|
27
31
|
await runStatsCommand(cmd);
|
|
28
32
|
}
|
|
@@ -188,11 +188,11 @@ export const KEYBINDINGS = {
|
|
|
188
188
|
},
|
|
189
189
|
"app.session.delete": {
|
|
190
190
|
defaultKeys: "ctrl+d",
|
|
191
|
-
description: "Delete session",
|
|
191
|
+
description: "Delete current session transcript/artifacts",
|
|
192
192
|
},
|
|
193
193
|
"app.session.deleteNoninvasive": {
|
|
194
194
|
defaultKeys: "ctrl+backspace",
|
|
195
|
-
description: "Delete session (non-invasive)",
|
|
195
|
+
description: "Delete selected session transcript/artifacts (non-invasive)",
|
|
196
196
|
},
|
|
197
197
|
"app.tree.foldOrUp": {
|
|
198
198
|
defaultKeys: ["ctrl+left", "alt+left"],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://raw.githubusercontent.com/jaybeyond/Sayknow_CLI/main/packages/coding-agent/src/config/mcp-schema.json",
|
|
4
4
|
"title": "SKC MCP configuration",
|
|
5
|
-
"description": "Schema for mcp.json, .mcp.json, .skc/mcp.json, and ~/.skc/agent/mcp.json
|
|
5
|
+
"description": "Schema for stored MCP server definitions in mcp.json, .mcp.json, .skc/mcp.json, and ~/.skc/agent/mcp.json. Normal standalone skc sessions do not consume skc mcp registrations as runtime tools today.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"properties": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"mcpServers": {
|
|
14
14
|
"type": "object",
|
|
15
|
-
"description": "Map of MCP server name to server configuration.",
|
|
15
|
+
"description": "Map of MCP server name to stored server configuration.",
|
|
16
16
|
"propertyNames": {
|
|
17
17
|
"pattern": "^[a-zA-Z0-9_.-]{1,100}$"
|
|
18
18
|
},
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"disabledServers": {
|
|
24
24
|
"type": "array",
|
|
25
|
-
"description": "
|
|
25
|
+
"description": "Denylist for explicit runtime MCP consumers that load discovered or stored servers by name.",
|
|
26
26
|
"items": {
|
|
27
27
|
"type": "string",
|
|
28
28
|
"minLength": 1
|
|
@@ -94,11 +94,11 @@
|
|
|
94
94
|
"properties": {
|
|
95
95
|
"enabled": {
|
|
96
96
|
"type": "boolean",
|
|
97
|
-
"description": "Whether
|
|
97
|
+
"description": "Whether explicit runtime MCP consumers should try to connect this server."
|
|
98
98
|
},
|
|
99
99
|
"autoload": {
|
|
100
100
|
"type": "boolean",
|
|
101
|
-
"description": "Whether
|
|
101
|
+
"description": "Whether an explicit runtime MCP consumer should connect this server automatically when that consumer starts (default: true). Normal standalone skc, skc --tmux, and print-mode sessions do not consume skc mcp registrations today; false keeps the server configured for consumers that support explicit connection."
|
|
102
102
|
},
|
|
103
103
|
"timeout": {
|
|
104
104
|
"type": "number",
|
|
@@ -114,13 +114,13 @@
|
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
"stdioServer": {
|
|
117
|
+
"type": "object",
|
|
118
|
+
"unevaluatedProperties": false,
|
|
117
119
|
"allOf": [
|
|
118
120
|
{
|
|
119
121
|
"$ref": "#/$defs/serverBase"
|
|
120
122
|
},
|
|
121
123
|
{
|
|
122
|
-
"type": "object",
|
|
123
|
-
"additionalProperties": false,
|
|
124
124
|
"required": ["command"],
|
|
125
125
|
"properties": {
|
|
126
126
|
"type": {
|
|
@@ -138,11 +138,15 @@
|
|
|
138
138
|
"items": {
|
|
139
139
|
"type": "string"
|
|
140
140
|
},
|
|
141
|
-
"description": "Arguments passed to the stdio server process."
|
|
141
|
+
"description": "Arguments passed to the stdio server process. Public CLI output redacts sensitive-looking argument values."
|
|
142
142
|
},
|
|
143
143
|
"env": {
|
|
144
144
|
"$ref": "#/$defs/stringMap",
|
|
145
|
-
"description": "Environment variables passed to the stdio process."
|
|
145
|
+
"description": "Environment variables passed to the stdio process. Public CLI output redacts values."
|
|
146
|
+
},
|
|
147
|
+
"noInheritEnv": {
|
|
148
|
+
"type": "boolean",
|
|
149
|
+
"description": "When true, explicit runtime consumers should avoid inheriting the host environment and pass only a minimal allowlist plus explicit env keys."
|
|
146
150
|
},
|
|
147
151
|
"cwd": {
|
|
148
152
|
"type": "string",
|
|
@@ -156,13 +160,13 @@
|
|
|
156
160
|
]
|
|
157
161
|
},
|
|
158
162
|
"httpServer": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"unevaluatedProperties": false,
|
|
159
165
|
"allOf": [
|
|
160
166
|
{
|
|
161
167
|
"$ref": "#/$defs/serverBase"
|
|
162
168
|
},
|
|
163
169
|
{
|
|
164
|
-
"type": "object",
|
|
165
|
-
"additionalProperties": false,
|
|
166
170
|
"required": ["type", "url"],
|
|
167
171
|
"properties": {
|
|
168
172
|
"type": {
|
|
@@ -173,11 +177,11 @@
|
|
|
173
177
|
"url": {
|
|
174
178
|
"type": "string",
|
|
175
179
|
"minLength": 1,
|
|
176
|
-
"description": "MCP endpoint URL."
|
|
180
|
+
"description": "MCP endpoint URL. Public CLI output redacts userinfo, query values, and fragments."
|
|
177
181
|
},
|
|
178
182
|
"headers": {
|
|
179
183
|
"$ref": "#/$defs/stringMap",
|
|
180
|
-
"description": "HTTP headers sent with MCP requests."
|
|
184
|
+
"description": "HTTP headers sent with MCP requests. Public CLI output redacts values."
|
|
181
185
|
}
|
|
182
186
|
},
|
|
183
187
|
"not": {
|
|
@@ -187,13 +191,13 @@
|
|
|
187
191
|
]
|
|
188
192
|
},
|
|
189
193
|
"sseServer": {
|
|
194
|
+
"type": "object",
|
|
195
|
+
"unevaluatedProperties": false,
|
|
190
196
|
"allOf": [
|
|
191
197
|
{
|
|
192
198
|
"$ref": "#/$defs/serverBase"
|
|
193
199
|
},
|
|
194
200
|
{
|
|
195
|
-
"type": "object",
|
|
196
|
-
"additionalProperties": false,
|
|
197
201
|
"required": ["type", "url"],
|
|
198
202
|
"properties": {
|
|
199
203
|
"type": {
|
|
@@ -204,11 +208,11 @@
|
|
|
204
208
|
"url": {
|
|
205
209
|
"type": "string",
|
|
206
210
|
"minLength": 1,
|
|
207
|
-
"description": "Legacy SSE endpoint URL."
|
|
211
|
+
"description": "Legacy SSE endpoint URL. Public CLI output redacts userinfo, query values, and fragments."
|
|
208
212
|
},
|
|
209
213
|
"headers": {
|
|
210
214
|
"$ref": "#/$defs/stringMap",
|
|
211
|
-
"description": "HTTP headers sent with the SSE transport."
|
|
215
|
+
"description": "HTTP headers sent with the SSE transport. Public CLI output redacts values."
|
|
212
216
|
}
|
|
213
217
|
},
|
|
214
218
|
"not": {
|
|
@@ -70,25 +70,25 @@ const profile = (
|
|
|
70
70
|
|
|
71
71
|
export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
72
72
|
profile("codex-eco", ["openai-codex"], {
|
|
73
|
-
default: "openai-codex/gpt-5.
|
|
74
|
-
executor: "openai-codex/gpt-5.
|
|
75
|
-
planner: "openai-codex/gpt-5.
|
|
76
|
-
critic: "openai-codex/gpt-5.
|
|
77
|
-
architect: "openai-codex/gpt-5.
|
|
73
|
+
default: "openai-codex/gpt-5.6-sol:medium",
|
|
74
|
+
executor: "openai-codex/gpt-5.6-luna:low",
|
|
75
|
+
planner: "openai-codex/gpt-5.6-luna:medium",
|
|
76
|
+
critic: "openai-codex/gpt-5.6-luna:medium",
|
|
77
|
+
architect: "openai-codex/gpt-5.6-sol:medium",
|
|
78
78
|
}),
|
|
79
79
|
profile("codex-medium", ["openai-codex"], {
|
|
80
|
-
default: "openai-codex/gpt-5.
|
|
81
|
-
executor: "openai-codex/gpt-5.
|
|
82
|
-
planner: "openai-codex/gpt-5.
|
|
83
|
-
critic: "openai-codex/gpt-5.
|
|
84
|
-
architect: "openai-codex/gpt-5.
|
|
80
|
+
default: "openai-codex/gpt-5.6-sol:high",
|
|
81
|
+
executor: "openai-codex/gpt-5.6-luna:medium",
|
|
82
|
+
planner: "openai-codex/gpt-5.6-terra:medium",
|
|
83
|
+
critic: "openai-codex/gpt-5.6-terra:high",
|
|
84
|
+
architect: "openai-codex/gpt-5.6-sol:high",
|
|
85
85
|
}),
|
|
86
86
|
profile("codex-pro", ["openai-codex"], {
|
|
87
|
-
default: "openai-codex/gpt-5.
|
|
88
|
-
executor: "openai-codex/gpt-5.
|
|
89
|
-
planner: "openai-codex/gpt-5.
|
|
90
|
-
critic: "openai-codex/gpt-5.
|
|
91
|
-
architect: "openai-codex/gpt-5.
|
|
87
|
+
default: "openai-codex/gpt-5.6-sol:xhigh",
|
|
88
|
+
executor: "openai-codex/gpt-5.6-terra:medium",
|
|
89
|
+
planner: "openai-codex/gpt-5.6-sol:high",
|
|
90
|
+
critic: "openai-codex/gpt-5.6-sol:xhigh",
|
|
91
|
+
architect: "openai-codex/gpt-5.6-sol:max",
|
|
92
92
|
}),
|
|
93
93
|
profile("opencodego", ["opencode-go"], {
|
|
94
94
|
default: "opencode-go/kimi-k2.6",
|
|
@@ -256,24 +256,24 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
|
|
|
256
256
|
}),
|
|
257
257
|
profile("opus-codex", ["anthropic", "openai-codex"], {
|
|
258
258
|
default: "anthropic/claude-opus-4-8:xhigh",
|
|
259
|
-
executor: "openai-codex/gpt-5.
|
|
260
|
-
planner: "openai-codex/gpt-5.
|
|
261
|
-
critic: "openai-codex/gpt-5.
|
|
262
|
-
architect: "openai-codex/gpt-5.
|
|
259
|
+
executor: "openai-codex/gpt-5.6-terra:low",
|
|
260
|
+
planner: "openai-codex/gpt-5.6-terra:medium",
|
|
261
|
+
critic: "openai-codex/gpt-5.6-terra:high",
|
|
262
|
+
architect: "openai-codex/gpt-5.6-sol:xhigh",
|
|
263
263
|
}),
|
|
264
264
|
profile("codex-opencodego", ["openai-codex", "opencode-go"], {
|
|
265
|
-
default: "openai-codex/gpt-5.
|
|
265
|
+
default: "openai-codex/gpt-5.6-sol:medium",
|
|
266
266
|
executor: "opencode-go/deepseek-v4-pro",
|
|
267
267
|
planner: "opencode-go/kimi-k2.6",
|
|
268
268
|
critic: "opencode-go/mimo-v2.5-pro",
|
|
269
|
-
architect: "openai-codex/gpt-5.
|
|
269
|
+
architect: "openai-codex/gpt-5.6-sol:xhigh",
|
|
270
270
|
}),
|
|
271
271
|
profile("fable-opus-codex", ["anthropic", "openai-codex"], {
|
|
272
272
|
default: "anthropic/claude-fable-5:high",
|
|
273
|
-
executor: "openai-codex/gpt-5.
|
|
273
|
+
executor: "openai-codex/gpt-5.6-terra:high",
|
|
274
274
|
planner: "anthropic/claude-opus-4-8:medium",
|
|
275
275
|
critic: "anthropic/claude-opus-4-8:high",
|
|
276
|
-
architect: "openai-codex/gpt-5.
|
|
276
|
+
architect: "openai-codex/gpt-5.6-sol:xhigh",
|
|
277
277
|
}),
|
|
278
278
|
];
|
|
279
279
|
|
package/src/discovery/builtin.ts
CHANGED
|
@@ -176,6 +176,19 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
176
176
|
autoload = undefined;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// Validate noInheritEnv: boolean only, warn on other types
|
|
180
|
+
let noInheritEnv: boolean | undefined;
|
|
181
|
+
if (serverConfig.noInheritEnv === undefined || serverConfig.noInheritEnv === null) {
|
|
182
|
+
noInheritEnv = undefined;
|
|
183
|
+
} else if (typeof serverConfig.noInheritEnv === "boolean") {
|
|
184
|
+
noInheritEnv = serverConfig.noInheritEnv;
|
|
185
|
+
} else {
|
|
186
|
+
logger.warn(
|
|
187
|
+
`MCP server "${serverName}": invalid noInheritEnv type ${typeof serverConfig.noInheritEnv}, ignoring`,
|
|
188
|
+
);
|
|
189
|
+
noInheritEnv = undefined;
|
|
190
|
+
}
|
|
191
|
+
|
|
179
192
|
result.push({
|
|
180
193
|
name: serverName,
|
|
181
194
|
enabled,
|
|
@@ -184,6 +197,7 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
184
197
|
command: serverConfig.command as string | undefined,
|
|
185
198
|
args: serverConfig.args as string[] | undefined,
|
|
186
199
|
env: serverConfig.env as Record<string, string> | undefined,
|
|
200
|
+
noInheritEnv,
|
|
187
201
|
cwd: serverConfig.cwd as string | undefined,
|
|
188
202
|
url: serverConfig.url as string | undefined,
|
|
189
203
|
headers: serverConfig.headers as Record<string, string> | undefined,
|
|
@@ -30,6 +30,7 @@ interface MCPConfigFile {
|
|
|
30
30
|
command?: string;
|
|
31
31
|
args?: string[];
|
|
32
32
|
env?: Record<string, string>;
|
|
33
|
+
noInheritEnv?: boolean;
|
|
33
34
|
cwd?: string;
|
|
34
35
|
url?: string;
|
|
35
36
|
headers?: Record<string, string>;
|
|
@@ -92,6 +93,18 @@ function transformMCPConfig(config: MCPConfigFile, source: SourceMeta): MCPServe
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
let noInheritEnv: boolean | undefined;
|
|
97
|
+
if (serverConfig.noInheritEnv !== undefined) {
|
|
98
|
+
if (typeof serverConfig.noInheritEnv === "boolean") {
|
|
99
|
+
noInheritEnv = serverConfig.noInheritEnv;
|
|
100
|
+
} else {
|
|
101
|
+
logger.warn("MCP server has invalid 'noInheritEnv' value, ignoring", {
|
|
102
|
+
name,
|
|
103
|
+
value: serverConfig.noInheritEnv,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
const server: MCPServer = {
|
|
96
109
|
name,
|
|
97
110
|
enabled,
|
|
@@ -100,6 +113,7 @@ function transformMCPConfig(config: MCPConfigFile, source: SourceMeta): MCPServe
|
|
|
100
113
|
command: serverConfig.command,
|
|
101
114
|
args: serverConfig.args,
|
|
102
115
|
env: serverConfig.env,
|
|
116
|
+
noInheritEnv,
|
|
103
117
|
cwd: serverConfig.cwd,
|
|
104
118
|
url: serverConfig.url,
|
|
105
119
|
headers: serverConfig.headers,
|
package/src/eval/js/executor.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_MAX_BYTES, OutputSink } from "../../session/streaming-output";
|
|
2
2
|
import type { ToolSession } from "../../tools";
|
|
3
3
|
import { resolveOutputMaxColumns, resolveOutputSinkHeadBytes } from "../../tools/output-meta";
|
|
4
|
+
import { ToolError } from "../../tools/tool-errors";
|
|
4
5
|
import { executeInVmContext, type JsDisplayOutput } from "./context-manager";
|
|
5
6
|
|
|
6
7
|
export interface JsExecutorOptions {
|
|
@@ -117,7 +118,12 @@ export async function executeJs(code: string, options: JsExecutorOptions): Promi
|
|
|
117
118
|
displayOutputs,
|
|
118
119
|
};
|
|
119
120
|
}
|
|
120
|
-
const message =
|
|
121
|
+
const message =
|
|
122
|
+
error instanceof ToolError || (error instanceof Error && error.name === "ToolError")
|
|
123
|
+
? error.message
|
|
124
|
+
: error instanceof Error
|
|
125
|
+
? (error.stack ?? error.message)
|
|
126
|
+
: String(error);
|
|
121
127
|
outputSink.push(message);
|
|
122
128
|
const summary = await outputSink.dump();
|
|
123
129
|
return {
|