@oh-my-pi/pi-coding-agent 15.0.1 → 15.1.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 +94 -1
- package/examples/custom-tools/README.md +11 -7
- package/examples/custom-tools/hello/index.ts +2 -2
- package/examples/extensions/README.md +19 -8
- package/examples/extensions/api-demo.ts +15 -19
- package/examples/extensions/hello.ts +5 -6
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/extensions/reload-runtime.ts +4 -3
- package/examples/extensions/with-deps/index.ts +4 -3
- package/examples/sdk/06-extensions.ts +4 -2
- package/package.json +8 -18
- package/src/autoresearch/tools/init-experiment.ts +38 -41
- package/src/autoresearch/tools/log-experiment.ts +32 -41
- package/src/autoresearch/tools/run-experiment.ts +3 -3
- package/src/autoresearch/tools/update-notes.ts +11 -11
- package/src/commands/commit.ts +10 -0
- package/src/commit/agentic/tools/analyze-file.ts +4 -4
- package/src/commit/agentic/tools/git-file-diff.ts +4 -4
- package/src/commit/agentic/tools/git-hunk.ts +5 -5
- package/src/commit/agentic/tools/git-overview.ts +4 -4
- package/src/commit/agentic/tools/propose-changelog.ts +13 -13
- package/src/commit/agentic/tools/propose-commit.ts +6 -6
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/schemas.ts +28 -28
- package/src/commit/agentic/tools/split-commit.ts +22 -21
- package/src/commit/analysis/summary.ts +4 -4
- package/src/commit/changelog/generate.ts +7 -11
- package/src/commit/shared-llm.ts +22 -34
- package/src/config/config-file.ts +35 -13
- package/src/config/model-registry.ts +40 -191
- package/src/config/models-config-schema.ts +166 -0
- package/src/config/settings-schema.ts +29 -0
- package/src/discovery/claude-plugins.ts +19 -7
- package/src/edit/index.ts +2 -2
- package/src/edit/modes/apply-patch.ts +7 -6
- package/src/edit/modes/patch.ts +18 -25
- package/src/edit/modes/replace.ts +18 -20
- package/src/eval/js/shared/rewrite-imports.ts +131 -10
- package/src/eval/py/executor.ts +233 -623
- package/src/eval/py/kernel.ts +27 -2
- package/src/eval/py/runner.py +42 -11
- package/src/eval/py/runtime.ts +1 -0
- package/src/exa/factory.ts +5 -4
- package/src/exa/mcp-client.ts +1 -1
- package/src/exa/researcher.ts +9 -20
- package/src/exa/search.ts +26 -52
- package/src/exa/types.ts +1 -1
- package/src/exa/websets.ts +54 -53
- package/src/exec/bash-executor.ts +2 -1
- package/src/extensibility/custom-commands/loader.ts +5 -3
- package/src/extensibility/custom-commands/types.ts +4 -2
- package/src/extensibility/custom-tools/loader.ts +5 -3
- package/src/extensibility/custom-tools/types.ts +7 -6
- package/src/extensibility/custom-tools/wrapper.ts +1 -1
- package/src/extensibility/extensions/get-commands-handler.ts +77 -0
- package/src/extensibility/extensions/loader.ts +7 -3
- package/src/extensibility/extensions/types.ts +9 -5
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/hooks/loader.ts +3 -1
- package/src/extensibility/hooks/tool-wrapper.ts +1 -1
- package/src/extensibility/hooks/types.ts +4 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +78 -31
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/typebox.ts +391 -0
- package/src/goals/tools/goal-tool.ts +6 -12
- package/src/hashline/input.ts +2 -1
- package/src/hashline/parser.ts +27 -3
- package/src/hashline/types.ts +4 -4
- package/src/hindsight/state.ts +2 -2
- package/src/index.ts +0 -2
- package/src/internal-urls/docs-index.generated.ts +15 -15
- package/src/internal-urls/router.ts +8 -0
- package/src/internal-urls/types.ts +21 -0
- package/src/lsp/config.ts +15 -6
- package/src/lsp/defaults.json +6 -2
- package/src/lsp/types.ts +30 -38
- package/src/mcp/manager.ts +1 -1
- package/src/mcp/tool-bridge.ts +1 -1
- package/src/modes/acp/acp-agent.ts +248 -50
- package/src/modes/components/session-observer-overlay.ts +12 -1
- package/src/modes/components/status-line/segments.ts +39 -4
- package/src/modes/controllers/command-controller.ts +27 -2
- package/src/modes/controllers/event-controller.ts +3 -4
- package/src/modes/controllers/extension-ui-controller.ts +3 -2
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/rpc/host-tools.ts +1 -1
- package/src/modes/rpc/host-uris.ts +235 -0
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-mode.ts +27 -1
- package/src/modes/rpc/rpc-types.ts +58 -1
- package/src/modes/runtime-init.ts +2 -1
- package/src/modes/theme/defaults/dark-poimandres.json +1 -0
- package/src/modes/theme/defaults/light-poimandres.json +1 -0
- package/src/modes/theme/theme.ts +117 -117
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/prompts/tools/github.md +4 -4
- package/src/prompts/tools/hashline.md +22 -26
- package/src/prompts/tools/read.md +55 -37
- package/src/sdk.ts +31 -8
- package/src/session/agent-session.ts +74 -104
- package/src/session/messages.ts +16 -51
- package/src/session/session-manager.ts +22 -2
- package/src/session/streaming-output.ts +16 -6
- package/src/task/discovery.ts +5 -2
- package/src/task/executor.ts +210 -87
- package/src/task/index.ts +15 -11
- package/src/task/render.ts +32 -5
- package/src/task/types.ts +54 -39
- package/src/tools/ask.ts +12 -12
- package/src/tools/ast-edit.ts +11 -15
- package/src/tools/ast-grep.ts +9 -10
- package/src/tools/bash-command-fixup.ts +47 -0
- package/src/tools/bash.ts +48 -38
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser.ts +39 -53
- package/src/tools/calculator.ts +12 -11
- package/src/tools/checkpoint.ts +7 -7
- package/src/tools/debug.ts +40 -43
- package/src/tools/eval.ts +16 -10
- package/src/tools/find.ts +10 -13
- package/src/tools/gh.ts +108 -132
- package/src/tools/hindsight-recall.ts +4 -6
- package/src/tools/hindsight-reflect.ts +5 -5
- package/src/tools/hindsight-retain.ts +15 -17
- package/src/tools/image-gen.ts +31 -81
- package/src/tools/index.ts +4 -1
- package/src/tools/inspect-image.ts +8 -9
- package/src/tools/irc.ts +15 -27
- package/src/tools/job.ts +30 -28
- package/src/tools/output-meta.ts +26 -0
- package/src/tools/read.ts +39 -12
- package/src/tools/recipe/index.ts +7 -9
- package/src/tools/render-mermaid.ts +12 -12
- package/src/tools/report-tool-issue.ts +4 -4
- package/src/tools/resolve.ts +11 -11
- package/src/tools/review.ts +14 -26
- package/src/tools/search-tool-bm25.ts +7 -9
- package/src/tools/search.ts +19 -22
- package/src/tools/ssh.ts +10 -9
- package/src/tools/todo-write.ts +26 -34
- package/src/tools/vim.ts +10 -26
- package/src/tools/write.ts +25 -5
- package/src/tools/yield.ts +100 -54
- package/src/web/search/index.ts +9 -24
- package/src/web/search/providers/anthropic.ts +5 -0
- package/src/web/search/providers/exa.ts +3 -0
- package/src/web/search/providers/gemini.ts +5 -0
- package/src/web/search/providers/jina.ts +5 -2
- package/src/web/search/providers/zai.ts +5 -2
- package/src/prompts/compaction/branch-summary-context.md +0 -5
- package/src/prompts/compaction/branch-summary-preamble.md +0 -2
- package/src/prompts/compaction/branch-summary.md +0 -30
- package/src/prompts/compaction/compaction-short-summary.md +0 -9
- package/src/prompts/compaction/compaction-summary-context.md +0 -5
- package/src/prompts/compaction/compaction-summary.md +0 -38
- package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
- package/src/prompts/compaction/compaction-update-summary.md +0 -45
- package/src/prompts/system/auto-handoff-threshold-focus.md +0 -1
- package/src/prompts/system/file-operations.md +0 -10
- package/src/prompts/system/handoff-document.md +0 -49
- package/src/prompts/system/summarization-system.md +0 -3
- package/src/session/compaction/branch-summarization.ts +0 -324
- package/src/session/compaction/compaction.ts +0 -1420
- package/src/session/compaction/errors.ts +0 -31
- package/src/session/compaction/index.ts +0 -8
- package/src/session/compaction/pruning.ts +0 -91
- package/src/session/compaction/utils.ts +0 -184
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getAgentDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import type { TSchema } from "@sinclair/typebox";
|
|
5
|
-
import { Value } from "@sinclair/typebox/value";
|
|
6
|
-
import type { ErrorObject } from "ajv";
|
|
7
4
|
import { JSONC, YAML } from "bun";
|
|
5
|
+
import type { ZodType } from "zod/v4";
|
|
6
|
+
|
|
7
|
+
/** Minimal subset of the AJV ConfigSchemaError shape this module actually relies on. */
|
|
8
|
+
interface ConfigSchemaError {
|
|
9
|
+
instancePath: string;
|
|
10
|
+
message: string | undefined;
|
|
11
|
+
}
|
|
8
12
|
|
|
9
13
|
function migrateJsonToYml(jsonPath: string, ymlPath: string) {
|
|
10
14
|
try {
|
|
@@ -25,7 +29,7 @@ function migrateJsonToYml(jsonPath: string, ymlPath: string) {
|
|
|
25
29
|
|
|
26
30
|
export interface IConfigFile<T> {
|
|
27
31
|
readonly id: string;
|
|
28
|
-
readonly schema:
|
|
32
|
+
readonly schema: ZodType<T>;
|
|
29
33
|
path?(): string;
|
|
30
34
|
load(): T | null;
|
|
31
35
|
invalidate?(): void;
|
|
@@ -35,7 +39,7 @@ export class ConfigError extends Error {
|
|
|
35
39
|
readonly #message: string;
|
|
36
40
|
constructor(
|
|
37
41
|
public readonly id: string,
|
|
38
|
-
public readonly schemaErrors:
|
|
42
|
+
public readonly schemaErrors: ConfigSchemaError[] | null | undefined,
|
|
39
43
|
public readonly other?: { err: unknown; stage: string },
|
|
40
44
|
) {
|
|
41
45
|
let messages: string[] | undefined;
|
|
@@ -68,7 +72,6 @@ export class ConfigError extends Error {
|
|
|
68
72
|
break;
|
|
69
73
|
default:
|
|
70
74
|
message = `${title}\n${messages!.map(m => ` - ${m}`).join("\n")}`;
|
|
71
|
-
break;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
super(message, { cause });
|
|
@@ -99,7 +102,7 @@ export class ConfigFile<T> implements IConfigFile<T> {
|
|
|
99
102
|
|
|
100
103
|
constructor(
|
|
101
104
|
readonly id: string,
|
|
102
|
-
readonly schema:
|
|
105
|
+
readonly schema: ZodType<T>,
|
|
103
106
|
configPath: string = path.join(getAgentDir(), `${id}.yml`),
|
|
104
107
|
) {
|
|
105
108
|
this.#basePath = configPath;
|
|
@@ -146,7 +149,14 @@ export class ConfigFile<T> implements IConfigFile<T> {
|
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
createDefault(): T {
|
|
149
|
-
|
|
152
|
+
const parsed = this.schema.safeParse({});
|
|
153
|
+
if (parsed.success) return parsed.data;
|
|
154
|
+
const fallback = this.schema.safeParse(undefined);
|
|
155
|
+
if (fallback.success) return fallback.data;
|
|
156
|
+
throw new ConfigError(this.id, undefined, {
|
|
157
|
+
err: new Error("Schema produced no default value"),
|
|
158
|
+
stage: "createDefault",
|
|
159
|
+
});
|
|
150
160
|
}
|
|
151
161
|
|
|
152
162
|
#storeCache(result: LoadResult<T>): LoadResult<T> {
|
|
@@ -169,17 +179,29 @@ export class ConfigFile<T> implements IConfigFile<T> {
|
|
|
169
179
|
throw new Error(`Invalid config file path: ${this.#basePath}`);
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
const checked = this.schema.safeParse(parsed);
|
|
183
|
+
if (!checked.success) {
|
|
184
|
+
const schemaErrors: ConfigSchemaError[] = [];
|
|
185
|
+
for (const issue of checked.error.issues) {
|
|
186
|
+
const instancePath = issue.path.length === 0 ? "" : `/${issue.path.map(String).join("/")}`;
|
|
187
|
+
schemaErrors.push({ instancePath, message: issue.message });
|
|
176
188
|
if (schemaErrors.length >= 50) break;
|
|
177
189
|
}
|
|
178
190
|
const error = new ConfigError(this.id, schemaErrors);
|
|
179
191
|
logger.warn("Failed to parse config file", { path: this.path(), error });
|
|
180
192
|
return this.#storeCache({ error, status: "error" });
|
|
181
193
|
}
|
|
182
|
-
|
|
194
|
+
const value = checked.data;
|
|
195
|
+
try {
|
|
196
|
+
this.#auxValidate?.(value);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
const wrapped =
|
|
199
|
+
error instanceof ConfigError
|
|
200
|
+
? error
|
|
201
|
+
: new ConfigError(this.id, undefined, { err: error, stage: "AuxValidate" });
|
|
202
|
+
return this.#storeCache({ error: wrapped, status: "error" });
|
|
203
|
+
}
|
|
204
|
+
return this.#storeCache({ value, status: "ok" });
|
|
183
205
|
} catch (error) {
|
|
184
206
|
if (isEnoent(error)) {
|
|
185
207
|
return this.#storeCache({ status: "not-found" });
|
|
@@ -30,7 +30,6 @@ const DEFAULT_LOCAL_TOKEN = "lm-studio-local";
|
|
|
30
30
|
import { registerOAuthProvider, unregisterOAuthProviders } from "@oh-my-pi/pi-ai/utils/oauth";
|
|
31
31
|
import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/utils/oauth/types";
|
|
32
32
|
import { isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
33
|
-
import { type Static, Type } from "@sinclair/typebox";
|
|
34
33
|
import { parseModelString, resolveProviderModelReference } from "../config/model-resolver";
|
|
35
34
|
import { isValidThemeColor, type ThemeColor } from "../modes/theme/theme";
|
|
36
35
|
import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
|
|
@@ -43,6 +42,13 @@ import {
|
|
|
43
42
|
formatCanonicalVariantSelector,
|
|
44
43
|
type ModelEquivalenceConfig,
|
|
45
44
|
} from "./model-equivalence";
|
|
45
|
+
import {
|
|
46
|
+
type ModelOverride,
|
|
47
|
+
type ModelsConfig,
|
|
48
|
+
ModelsConfigSchema,
|
|
49
|
+
type ProviderAuthMode,
|
|
50
|
+
type ProviderDiscovery,
|
|
51
|
+
} from "./models-config-schema";
|
|
46
52
|
import { type Settings, settings } from "./settings";
|
|
47
53
|
|
|
48
54
|
export type { CanonicalModelIndex, CanonicalModelRecord, CanonicalModelVariant, ModelEquivalenceConfig };
|
|
@@ -121,194 +127,6 @@ export function getRoleInfo(role: string, settings: Settings): RoleInfo {
|
|
|
121
127
|
return { name: role, color: "muted" };
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
const OpenRouterRoutingSchema = Type.Object({
|
|
125
|
-
only: Type.Optional(Type.Array(Type.String())),
|
|
126
|
-
order: Type.Optional(Type.Array(Type.String())),
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Schema for Vercel AI Gateway routing preferences
|
|
130
|
-
const VercelGatewayRoutingSchema = Type.Object({
|
|
131
|
-
only: Type.Optional(Type.Array(Type.String())),
|
|
132
|
-
order: Type.Optional(Type.Array(Type.String())),
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Schema for OpenAI compatibility settings
|
|
136
|
-
const ReasoningEffortMapSchema = Type.Object({
|
|
137
|
-
minimal: Type.Optional(Type.String()),
|
|
138
|
-
low: Type.Optional(Type.String()),
|
|
139
|
-
medium: Type.Optional(Type.String()),
|
|
140
|
-
high: Type.Optional(Type.String()),
|
|
141
|
-
xhigh: Type.Optional(Type.String()),
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
const OpenAICompatSchema = Type.Object({
|
|
145
|
-
supportsStore: Type.Optional(Type.Boolean()),
|
|
146
|
-
supportsDeveloperRole: Type.Optional(Type.Boolean()),
|
|
147
|
-
supportsReasoningEffort: Type.Optional(Type.Boolean()),
|
|
148
|
-
reasoningEffortMap: Type.Optional(ReasoningEffortMapSchema),
|
|
149
|
-
maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
|
|
150
|
-
supportsUsageInStreaming: Type.Optional(Type.Boolean()),
|
|
151
|
-
requiresToolResultName: Type.Optional(Type.Boolean()),
|
|
152
|
-
requiresMistralToolIds: Type.Optional(Type.Boolean()),
|
|
153
|
-
requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
|
|
154
|
-
requiresThinkingAsText: Type.Optional(Type.Boolean()),
|
|
155
|
-
reasoningContentField: Type.Optional(
|
|
156
|
-
Type.Union([Type.Literal("reasoning_content"), Type.Literal("reasoning"), Type.Literal("reasoning_text")]),
|
|
157
|
-
),
|
|
158
|
-
requiresReasoningContentForToolCalls: Type.Optional(Type.Boolean()),
|
|
159
|
-
requiresAssistantContentForToolCalls: Type.Optional(Type.Boolean()),
|
|
160
|
-
supportsToolChoice: Type.Optional(Type.Boolean()),
|
|
161
|
-
disableReasoningOnForcedToolChoice: Type.Optional(Type.Boolean()),
|
|
162
|
-
thinkingFormat: Type.Optional(
|
|
163
|
-
Type.Union([
|
|
164
|
-
Type.Literal("openai"),
|
|
165
|
-
Type.Literal("openrouter"),
|
|
166
|
-
Type.Literal("zai"),
|
|
167
|
-
Type.Literal("qwen"),
|
|
168
|
-
Type.Literal("qwen-chat-template"),
|
|
169
|
-
]),
|
|
170
|
-
),
|
|
171
|
-
openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
|
|
172
|
-
vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
|
|
173
|
-
extraBody: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
174
|
-
supportsStrictMode: Type.Optional(Type.Boolean()),
|
|
175
|
-
toolStrictMode: Type.Optional(Type.Union([Type.Literal("all_strict"), Type.Literal("none")])),
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
const EffortSchema = Type.Union([
|
|
179
|
-
Type.Literal("minimal"),
|
|
180
|
-
Type.Literal("low"),
|
|
181
|
-
Type.Literal("medium"),
|
|
182
|
-
Type.Literal("high"),
|
|
183
|
-
Type.Literal("xhigh"),
|
|
184
|
-
]);
|
|
185
|
-
|
|
186
|
-
const ThinkingControlModeSchema = Type.Union([
|
|
187
|
-
Type.Literal("effort"),
|
|
188
|
-
Type.Literal("budget"),
|
|
189
|
-
Type.Literal("google-level"),
|
|
190
|
-
Type.Literal("anthropic-adaptive"),
|
|
191
|
-
Type.Literal("anthropic-budget-effort"),
|
|
192
|
-
]);
|
|
193
|
-
|
|
194
|
-
const ModelThinkingSchema = Type.Object({
|
|
195
|
-
minLevel: EffortSchema,
|
|
196
|
-
maxLevel: EffortSchema,
|
|
197
|
-
mode: ThinkingControlModeSchema,
|
|
198
|
-
defaultLevel: Type.Optional(EffortSchema),
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// Schema for custom model definition
|
|
202
|
-
// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
|
|
203
|
-
const ModelDefinitionSchema = Type.Object({
|
|
204
|
-
id: Type.String({ minLength: 1 }),
|
|
205
|
-
name: Type.Optional(Type.String({ minLength: 1 })),
|
|
206
|
-
api: Type.Optional(
|
|
207
|
-
Type.Union([
|
|
208
|
-
Type.Literal("openai-completions"),
|
|
209
|
-
Type.Literal("openai-responses"),
|
|
210
|
-
Type.Literal("openai-codex-responses"),
|
|
211
|
-
Type.Literal("azure-openai-responses"),
|
|
212
|
-
Type.Literal("anthropic-messages"),
|
|
213
|
-
Type.Literal("google-generative-ai"),
|
|
214
|
-
Type.Literal("google-vertex"),
|
|
215
|
-
]),
|
|
216
|
-
),
|
|
217
|
-
baseUrl: Type.Optional(Type.String({ minLength: 1 })),
|
|
218
|
-
reasoning: Type.Optional(Type.Boolean()),
|
|
219
|
-
thinking: Type.Optional(ModelThinkingSchema),
|
|
220
|
-
input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
|
|
221
|
-
cost: Type.Optional(
|
|
222
|
-
Type.Object({
|
|
223
|
-
input: Type.Number(),
|
|
224
|
-
output: Type.Number(),
|
|
225
|
-
cacheRead: Type.Number(),
|
|
226
|
-
cacheWrite: Type.Number(),
|
|
227
|
-
}),
|
|
228
|
-
),
|
|
229
|
-
premiumMultiplier: Type.Optional(Type.Number()),
|
|
230
|
-
contextWindow: Type.Optional(Type.Number()),
|
|
231
|
-
maxTokens: Type.Optional(Type.Number()),
|
|
232
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
233
|
-
compat: Type.Optional(OpenAICompatSchema),
|
|
234
|
-
contextPromotionTarget: Type.Optional(Type.String({ minLength: 1 })),
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// Schema for per-model overrides (all fields optional, merged with built-in model)
|
|
238
|
-
const ModelOverrideSchema = Type.Object({
|
|
239
|
-
name: Type.Optional(Type.String({ minLength: 1 })),
|
|
240
|
-
reasoning: Type.Optional(Type.Boolean()),
|
|
241
|
-
thinking: Type.Optional(ModelThinkingSchema),
|
|
242
|
-
input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
|
|
243
|
-
cost: Type.Optional(
|
|
244
|
-
Type.Object({
|
|
245
|
-
input: Type.Optional(Type.Number()),
|
|
246
|
-
output: Type.Optional(Type.Number()),
|
|
247
|
-
cacheRead: Type.Optional(Type.Number()),
|
|
248
|
-
cacheWrite: Type.Optional(Type.Number()),
|
|
249
|
-
}),
|
|
250
|
-
),
|
|
251
|
-
premiumMultiplier: Type.Optional(Type.Number()),
|
|
252
|
-
contextWindow: Type.Optional(Type.Number()),
|
|
253
|
-
maxTokens: Type.Optional(Type.Number()),
|
|
254
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
255
|
-
compat: Type.Optional(OpenAICompatSchema),
|
|
256
|
-
contextPromotionTarget: Type.Optional(Type.String({ minLength: 1 })),
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
type ModelOverride = Static<typeof ModelOverrideSchema>;
|
|
260
|
-
|
|
261
|
-
const ProviderDiscoverySchema = Type.Object({
|
|
262
|
-
type: Type.Union([
|
|
263
|
-
Type.Literal("ollama"),
|
|
264
|
-
Type.Literal("llama.cpp"),
|
|
265
|
-
Type.Literal("lm-studio"),
|
|
266
|
-
Type.Literal("openai-models-list"),
|
|
267
|
-
]),
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
const ProviderAuthSchema = Type.Union([Type.Literal("apiKey"), Type.Literal("none"), Type.Literal("oauth")]);
|
|
271
|
-
|
|
272
|
-
const ProviderConfigSchema = Type.Object({
|
|
273
|
-
baseUrl: Type.Optional(Type.String({ minLength: 1 })),
|
|
274
|
-
apiKey: Type.Optional(Type.String({ minLength: 1 })),
|
|
275
|
-
api: Type.Optional(
|
|
276
|
-
Type.Union([
|
|
277
|
-
Type.Literal("openai-completions"),
|
|
278
|
-
Type.Literal("openai-responses"),
|
|
279
|
-
Type.Literal("openai-codex-responses"),
|
|
280
|
-
Type.Literal("azure-openai-responses"),
|
|
281
|
-
Type.Literal("anthropic-messages"),
|
|
282
|
-
Type.Literal("google-generative-ai"),
|
|
283
|
-
Type.Literal("google-vertex"),
|
|
284
|
-
]),
|
|
285
|
-
),
|
|
286
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
287
|
-
compat: Type.Optional(OpenAICompatSchema),
|
|
288
|
-
authHeader: Type.Optional(Type.Boolean()),
|
|
289
|
-
auth: Type.Optional(ProviderAuthSchema),
|
|
290
|
-
discovery: Type.Optional(ProviderDiscoverySchema),
|
|
291
|
-
models: Type.Optional(Type.Array(ModelDefinitionSchema)),
|
|
292
|
-
modelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),
|
|
293
|
-
/** When true, disables strict tool schemas for this provider (for third-party Anthropic-compatible endpoints that reject the strict field). */
|
|
294
|
-
disableStrictTools: Type.Optional(Type.Boolean()),
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
const EquivalenceConfigSchema = Type.Object({
|
|
298
|
-
overrides: Type.Optional(Type.Record(Type.String(), Type.String({ minLength: 1 }))),
|
|
299
|
-
exclude: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const ModelsConfigSchema = Type.Object({
|
|
303
|
-
providers: Type.Optional(Type.Record(Type.String(), ProviderConfigSchema)),
|
|
304
|
-
equivalence: Type.Optional(EquivalenceConfigSchema),
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
type ModelsConfig = Static<typeof ModelsConfigSchema>;
|
|
308
|
-
|
|
309
|
-
type ProviderAuthMode = Static<typeof ProviderAuthSchema>;
|
|
310
|
-
type ProviderDiscovery = Static<typeof ProviderDiscoverySchema>;
|
|
311
|
-
|
|
312
130
|
type ProviderValidationMode = "models-config" | "runtime-register";
|
|
313
131
|
|
|
314
132
|
interface ProviderValidationModel {
|
|
@@ -347,12 +165,13 @@ function validateProviderConfiguration(
|
|
|
347
165
|
!config.baseUrl &&
|
|
348
166
|
!config.headers &&
|
|
349
167
|
!config.compat &&
|
|
168
|
+
!config.apiKey &&
|
|
350
169
|
!config.disableStrictTools &&
|
|
351
170
|
!hasModelOverrides &&
|
|
352
171
|
!config.discovery
|
|
353
172
|
) {
|
|
354
173
|
throw new Error(
|
|
355
|
-
`Provider ${providerName}: must specify "baseUrl", "headers", "compat", "disableStrictTools", "modelOverrides", "discovery", or "models"`,
|
|
174
|
+
`Provider ${providerName}: must specify "baseUrl", "headers", "apiKey", "compat", "disableStrictTools", "modelOverrides", "discovery", or "models"`,
|
|
356
175
|
);
|
|
357
176
|
}
|
|
358
177
|
}
|
|
@@ -1015,8 +834,12 @@ export class ModelRegistry {
|
|
|
1015
834
|
|
|
1016
835
|
this.#addImplicitDiscoverableProviders(configuredProviders);
|
|
1017
836
|
const builtInModels = this.#applyHardcodedModelPolicies(this.#loadBuiltInModels(overrides));
|
|
837
|
+
const cachedStandardModels = this.#applyHardcodedModelPolicies(this.#loadCachedStandardProviderModels());
|
|
1018
838
|
const cachedDiscoveries = this.#applyHardcodedModelPolicies(this.#loadCachedDiscoverableModels());
|
|
1019
|
-
const resolvedDefaults = this.#mergeResolvedModels(
|
|
839
|
+
const resolvedDefaults = this.#mergeResolvedModels(
|
|
840
|
+
this.#mergeResolvedModels(builtInModels, cachedStandardModels),
|
|
841
|
+
cachedDiscoveries,
|
|
842
|
+
);
|
|
1020
843
|
const withConfigModels = this.#mergeCustomModels(resolvedDefaults, this.#customModelOverlays);
|
|
1021
844
|
// Merge runtime extension models so they survive refresh() cycles
|
|
1022
845
|
const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
|
|
@@ -1115,6 +938,32 @@ export class ModelRegistry {
|
|
|
1115
938
|
return merged;
|
|
1116
939
|
}
|
|
1117
940
|
|
|
941
|
+
#loadCachedStandardProviderModels(): Model<Api>[] {
|
|
942
|
+
const configuredDiscoveryProviders = new Set(this.#discoverableProviders.map(provider => provider.provider));
|
|
943
|
+
const cachedModels: Model<Api>[] = [];
|
|
944
|
+
for (const descriptor of PROVIDER_DESCRIPTORS) {
|
|
945
|
+
if (configuredDiscoveryProviders.has(descriptor.providerId)) {
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
const cache = readModelCache<Api>(descriptor.providerId, 24 * 60 * 60 * 1000, Date.now, this.#cacheDbPath);
|
|
949
|
+
if (!cache) {
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const models = cache.models.map(model =>
|
|
953
|
+
model.provider === descriptor.providerId ? model : { ...model, provider: descriptor.providerId },
|
|
954
|
+
);
|
|
955
|
+
const providerOverride = this.#providerOverrides.get(descriptor.providerId);
|
|
956
|
+
const withTransport = providerOverride
|
|
957
|
+
? models.map(model => this.#applyProviderTransportOverride(model, providerOverride))
|
|
958
|
+
: models;
|
|
959
|
+
const withCompat = providerOverride?.compat
|
|
960
|
+
? withTransport.map(model => ({ ...model, compat: mergeCompat(model.compat, providerOverride.compat) }))
|
|
961
|
+
: withTransport;
|
|
962
|
+
cachedModels.push(...this.#applyProviderModelOverrides(descriptor.providerId, withCompat));
|
|
963
|
+
}
|
|
964
|
+
return cachedModels;
|
|
965
|
+
}
|
|
966
|
+
|
|
1118
967
|
#loadCachedDiscoverableModels(): Model<Api>[] {
|
|
1119
968
|
const cachedModels: Model<Api>[] = [];
|
|
1120
969
|
for (const providerConfig of this.#discoverableProviders) {
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
|
|
3
|
+
const OpenRouterRoutingSchema = z.object({
|
|
4
|
+
only: z.array(z.string()).optional(),
|
|
5
|
+
order: z.array(z.string()).optional(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const VercelGatewayRoutingSchema = z.object({
|
|
9
|
+
only: z.array(z.string()).optional(),
|
|
10
|
+
order: z.array(z.string()).optional(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const ReasoningEffortMapSchema = z.object({
|
|
14
|
+
minimal: z.string().optional(),
|
|
15
|
+
low: z.string().optional(),
|
|
16
|
+
medium: z.string().optional(),
|
|
17
|
+
high: z.string().optional(),
|
|
18
|
+
xhigh: z.string().optional(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const OpenAICompatSchema = z.object({
|
|
22
|
+
supportsStore: z.boolean().optional(),
|
|
23
|
+
supportsDeveloperRole: z.boolean().optional(),
|
|
24
|
+
supportsMultipleSystemMessages: z.boolean().optional(),
|
|
25
|
+
supportsReasoningEffort: z.boolean().optional(),
|
|
26
|
+
reasoningEffortMap: ReasoningEffortMapSchema.optional(),
|
|
27
|
+
maxTokensField: z.enum(["max_completion_tokens", "max_tokens"]).optional(),
|
|
28
|
+
supportsUsageInStreaming: z.boolean().optional(),
|
|
29
|
+
requiresToolResultName: z.boolean().optional(),
|
|
30
|
+
requiresMistralToolIds: z.boolean().optional(),
|
|
31
|
+
requiresAssistantAfterToolResult: z.boolean().optional(),
|
|
32
|
+
requiresThinkingAsText: z.boolean().optional(),
|
|
33
|
+
reasoningContentField: z.enum(["reasoning_content", "reasoning", "reasoning_text"]).optional(),
|
|
34
|
+
requiresReasoningContentForToolCalls: z.boolean().optional(),
|
|
35
|
+
allowsSyntheticReasoningContentForToolCalls: z.boolean().optional(),
|
|
36
|
+
requiresAssistantContentForToolCalls: z.boolean().optional(),
|
|
37
|
+
supportsToolChoice: z.boolean().optional(),
|
|
38
|
+
disableReasoningOnForcedToolChoice: z.boolean().optional(),
|
|
39
|
+
disableReasoningOnToolChoice: z.boolean().optional(),
|
|
40
|
+
thinkingFormat: z.enum(["openai", "openrouter", "zai", "qwen", "qwen-chat-template"]).optional(),
|
|
41
|
+
openRouterRouting: OpenRouterRoutingSchema.optional(),
|
|
42
|
+
vercelGatewayRouting: VercelGatewayRoutingSchema.optional(),
|
|
43
|
+
extraBody: z.record(z.string(), z.unknown()).optional(),
|
|
44
|
+
supportsStrictMode: z.boolean().optional(),
|
|
45
|
+
toolStrictMode: z.enum(["all_strict", "none"]).optional(),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const EffortSchema = z.enum(["minimal", "low", "medium", "high", "xhigh"]);
|
|
49
|
+
|
|
50
|
+
const ThinkingControlModeSchema = z.enum([
|
|
51
|
+
"effort",
|
|
52
|
+
"budget",
|
|
53
|
+
"google-level",
|
|
54
|
+
"anthropic-adaptive",
|
|
55
|
+
"anthropic-budget-effort",
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
const ModelThinkingSchema = z.object({
|
|
59
|
+
minLevel: EffortSchema,
|
|
60
|
+
maxLevel: EffortSchema,
|
|
61
|
+
mode: ThinkingControlModeSchema,
|
|
62
|
+
defaultLevel: EffortSchema.optional(),
|
|
63
|
+
levels: z.array(EffortSchema).optional(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const ModelDefinitionSchema = z.object({
|
|
67
|
+
id: z.string().min(1),
|
|
68
|
+
name: z.string().min(1).optional(),
|
|
69
|
+
api: z
|
|
70
|
+
.enum([
|
|
71
|
+
"openai-completions",
|
|
72
|
+
"openai-responses",
|
|
73
|
+
"openai-codex-responses",
|
|
74
|
+
"azure-openai-responses",
|
|
75
|
+
"anthropic-messages",
|
|
76
|
+
"google-generative-ai",
|
|
77
|
+
"google-vertex",
|
|
78
|
+
])
|
|
79
|
+
.optional(),
|
|
80
|
+
baseUrl: z.string().min(1).optional(),
|
|
81
|
+
reasoning: z.boolean().optional(),
|
|
82
|
+
thinking: ModelThinkingSchema.optional(),
|
|
83
|
+
input: z.array(z.enum(["text", "image"])).optional(),
|
|
84
|
+
cost: z
|
|
85
|
+
.object({
|
|
86
|
+
input: z.number(),
|
|
87
|
+
output: z.number(),
|
|
88
|
+
cacheRead: z.number(),
|
|
89
|
+
cacheWrite: z.number(),
|
|
90
|
+
})
|
|
91
|
+
.optional(),
|
|
92
|
+
premiumMultiplier: z.number().optional(),
|
|
93
|
+
contextWindow: z.number().optional(),
|
|
94
|
+
maxTokens: z.number().optional(),
|
|
95
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
96
|
+
compat: OpenAICompatSchema.optional(),
|
|
97
|
+
contextPromotionTarget: z.string().min(1).optional(),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export const ModelOverrideSchema = z.object({
|
|
101
|
+
name: z.string().min(1).optional(),
|
|
102
|
+
reasoning: z.boolean().optional(),
|
|
103
|
+
thinking: ModelThinkingSchema.optional(),
|
|
104
|
+
input: z.array(z.enum(["text", "image"])).optional(),
|
|
105
|
+
cost: z
|
|
106
|
+
.object({
|
|
107
|
+
input: z.number().optional(),
|
|
108
|
+
output: z.number().optional(),
|
|
109
|
+
cacheRead: z.number().optional(),
|
|
110
|
+
cacheWrite: z.number().optional(),
|
|
111
|
+
})
|
|
112
|
+
.optional(),
|
|
113
|
+
premiumMultiplier: z.number().optional(),
|
|
114
|
+
contextWindow: z.number().optional(),
|
|
115
|
+
maxTokens: z.number().optional(),
|
|
116
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
117
|
+
compat: OpenAICompatSchema.optional(),
|
|
118
|
+
contextPromotionTarget: z.string().min(1).optional(),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export type ModelOverride = z.infer<typeof ModelOverrideSchema>;
|
|
122
|
+
|
|
123
|
+
export const ProviderDiscoverySchema = z.object({
|
|
124
|
+
type: z.enum(["ollama", "llama.cpp", "lm-studio", "openai-models-list"]),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export const ProviderAuthSchema = z.enum(["apiKey", "none", "oauth"]);
|
|
128
|
+
|
|
129
|
+
export type ProviderAuthMode = z.infer<typeof ProviderAuthSchema>;
|
|
130
|
+
export type ProviderDiscovery = z.infer<typeof ProviderDiscoverySchema>;
|
|
131
|
+
|
|
132
|
+
const ProviderConfigSchema = z.object({
|
|
133
|
+
baseUrl: z.string().min(1).optional(),
|
|
134
|
+
apiKey: z.string().min(1).optional(),
|
|
135
|
+
api: z
|
|
136
|
+
.enum([
|
|
137
|
+
"openai-completions",
|
|
138
|
+
"openai-responses",
|
|
139
|
+
"openai-codex-responses",
|
|
140
|
+
"azure-openai-responses",
|
|
141
|
+
"anthropic-messages",
|
|
142
|
+
"google-generative-ai",
|
|
143
|
+
"google-vertex",
|
|
144
|
+
])
|
|
145
|
+
.optional(),
|
|
146
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
147
|
+
compat: OpenAICompatSchema.optional(),
|
|
148
|
+
authHeader: z.boolean().optional(),
|
|
149
|
+
auth: ProviderAuthSchema.optional(),
|
|
150
|
+
discovery: ProviderDiscoverySchema.optional(),
|
|
151
|
+
models: z.array(ModelDefinitionSchema).optional(),
|
|
152
|
+
modelOverrides: z.record(z.string(), ModelOverrideSchema).optional(),
|
|
153
|
+
disableStrictTools: z.boolean().optional(),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const EquivalenceConfigSchema = z.object({
|
|
157
|
+
overrides: z.record(z.string(), z.string().min(1)).optional(),
|
|
158
|
+
exclude: z.array(z.string().min(1)).optional(),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
export const ModelsConfigSchema = z.object({
|
|
162
|
+
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
163
|
+
equivalence: EquivalenceConfigSchema.optional(),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
export type ModelsConfig = z.infer<typeof ModelsConfigSchema>;
|
|
@@ -1648,6 +1648,17 @@ export const SETTINGS_SCHEMA = {
|
|
|
1648
1648
|
},
|
|
1649
1649
|
"bashInterceptor.patterns": { type: "array", default: DEFAULT_BASH_INTERCEPTOR_RULES },
|
|
1650
1650
|
|
|
1651
|
+
"bash.stripTrailingHeadTail": {
|
|
1652
|
+
type: "boolean",
|
|
1653
|
+
default: true,
|
|
1654
|
+
ui: {
|
|
1655
|
+
tab: "editing",
|
|
1656
|
+
label: "Strip Trailing head/tail",
|
|
1657
|
+
description:
|
|
1658
|
+
"Silently drop trailing `| head`/`| tail` pipes from single-line bash commands. Output is already truncated automatically.",
|
|
1659
|
+
},
|
|
1660
|
+
},
|
|
1661
|
+
|
|
1651
1662
|
// Shell output minimizer
|
|
1652
1663
|
"shellMinimizer.enabled": {
|
|
1653
1664
|
type: "boolean",
|
|
@@ -2318,6 +2329,24 @@ export const SETTINGS_SCHEMA = {
|
|
|
2318
2329
|
},
|
|
2319
2330
|
},
|
|
2320
2331
|
|
|
2332
|
+
"task.maxRuntimeMs": {
|
|
2333
|
+
type: "number",
|
|
2334
|
+
default: 0,
|
|
2335
|
+
ui: {
|
|
2336
|
+
tab: "tasks",
|
|
2337
|
+
label: "Max Subagent Runtime",
|
|
2338
|
+
description:
|
|
2339
|
+
"Hard wall-clock limit per subagent (ms). 0 disables it. Defense-in-depth against provider-side stream hangs that escape the inference-layer watchdog; triggers a normal subagent abort with a 'timed out' reason.",
|
|
2340
|
+
options: [
|
|
2341
|
+
{ value: "0", label: "Unlimited", description: "Default" },
|
|
2342
|
+
{ value: "300000", label: "5 minutes" },
|
|
2343
|
+
{ value: "900000", label: "15 minutes" },
|
|
2344
|
+
{ value: "1800000", label: "30 minutes" },
|
|
2345
|
+
{ value: "3600000", label: "1 hour" },
|
|
2346
|
+
],
|
|
2347
|
+
},
|
|
2348
|
+
},
|
|
2349
|
+
|
|
2321
2350
|
"task.disabledAgents": {
|
|
2322
2351
|
type: "array",
|
|
2323
2352
|
default: [] as string[],
|
|
@@ -31,6 +31,7 @@ const PRIORITY = 70; // Below claude.ts (80) so user .claude/ overrides win
|
|
|
31
31
|
interface ClaudePluginManifest {
|
|
32
32
|
skills?: string;
|
|
33
33
|
"slash-commands"?: string;
|
|
34
|
+
commands?: string;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
interface ResolvedPluginDir {
|
|
@@ -59,24 +60,35 @@ function isWithinPluginRoot(rootPath: string, targetPath: string): boolean {
|
|
|
59
60
|
|
|
60
61
|
async function resolvePluginDir(
|
|
61
62
|
root: ClaudePluginRoot,
|
|
62
|
-
|
|
63
|
+
manifestKeys: ReadonlyArray<keyof ClaudePluginManifest>,
|
|
63
64
|
fallback: string,
|
|
64
65
|
): Promise<ResolvedPluginDir> {
|
|
65
66
|
const manifest = await readPluginManifest(root);
|
|
66
67
|
const fallbackDir = path.join(root.path, fallback);
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
|
|
69
|
+
let configured: string | undefined;
|
|
70
|
+
let matchedKey: keyof ClaudePluginManifest | undefined;
|
|
71
|
+
for (const key of manifestKeys) {
|
|
72
|
+
const val = manifest?.[key];
|
|
73
|
+
if (typeof val === "string" && val.trim()) {
|
|
74
|
+
configured = val.trim();
|
|
75
|
+
matchedKey = key;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (configured === undefined) {
|
|
69
81
|
return { dir: fallbackDir };
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
const resolved = path.resolve(root.path, configured
|
|
84
|
+
const resolved = path.resolve(root.path, configured);
|
|
73
85
|
if (isWithinPluginRoot(root.path, resolved)) {
|
|
74
86
|
return { dir: resolved };
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
return {
|
|
78
90
|
dir: fallbackDir,
|
|
79
|
-
warning: `[claude-plugins] Ignoring ${String(
|
|
91
|
+
warning: `[claude-plugins] Ignoring ${String(matchedKey)} path outside plugin root for ${root.id}: ${configured}`,
|
|
80
92
|
};
|
|
81
93
|
}
|
|
82
94
|
|
|
@@ -93,7 +105,7 @@ async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
|
|
|
93
105
|
|
|
94
106
|
const results = await Promise.all(
|
|
95
107
|
roots.map(async root => {
|
|
96
|
-
const { dir: skillsDir, warning } = await resolvePluginDir(root, "skills", "skills");
|
|
108
|
+
const { dir: skillsDir, warning } = await resolvePluginDir(root, ["skills"], "skills");
|
|
97
109
|
const result = await scanSkillsFromDir(ctx, {
|
|
98
110
|
dir: skillsDir,
|
|
99
111
|
providerId: PROVIDER_ID,
|
|
@@ -128,7 +140,7 @@ async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashComm
|
|
|
128
140
|
|
|
129
141
|
const results = await Promise.all(
|
|
130
142
|
roots.map(async root => {
|
|
131
|
-
const { dir: commandsDir, warning } = await resolvePluginDir(root, "slash-commands", "commands");
|
|
143
|
+
const { dir: commandsDir, warning } = await resolvePluginDir(root, ["commands", "slash-commands"], "commands");
|
|
132
144
|
const result = await loadFilesFromDir<SlashCommand>(ctx, commandsDir, PROVIDER_ID, root.scope, {
|
|
133
145
|
extensions: ["md"],
|
|
134
146
|
transform: (name, content, filePath, source) => {
|
package/src/edit/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
3
|
-
import type
|
|
3
|
+
import type * as z from "zod/v4";
|
|
4
4
|
import {
|
|
5
5
|
executeHashlineSingle,
|
|
6
6
|
HashlineMismatchError,
|
|
@@ -53,7 +53,7 @@ type TInput =
|
|
|
53
53
|
| typeof vimSchema
|
|
54
54
|
| typeof applyPatchSchema;
|
|
55
55
|
|
|
56
|
-
type VimParams =
|
|
56
|
+
type VimParams = z.infer<typeof vimSchema>;
|
|
57
57
|
type EditParams = ReplaceParams | PatchParams | HashlineParams | VimParams | ApplyPatchParams;
|
|
58
58
|
type EditToolResultDetails = EditToolDetails | VimToolDetails;
|
|
59
59
|
|