@yeshwanthyk/runtime-effect 0.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/README.md +19 -0
- package/dist/agent.d.ts +15 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +28 -0
- package/dist/agent.js.map +1 -0
- package/dist/config.d.ts +65 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +232 -0
- package/dist/config.js.map +1 -0
- package/dist/extensibility/custom-commands.d.ts +51 -0
- package/dist/extensibility/custom-commands.d.ts.map +1 -0
- package/dist/extensibility/custom-commands.js +139 -0
- package/dist/extensibility/custom-commands.js.map +1 -0
- package/dist/extensibility/custom-tools/index.d.ts +6 -0
- package/dist/extensibility/custom-tools/index.d.ts.map +1 -0
- package/dist/extensibility/custom-tools/index.js +5 -0
- package/dist/extensibility/custom-tools/index.js.map +1 -0
- package/dist/extensibility/custom-tools/loader.d.ts +24 -0
- package/dist/extensibility/custom-tools/loader.d.ts.map +1 -0
- package/dist/extensibility/custom-tools/loader.js +219 -0
- package/dist/extensibility/custom-tools/loader.js.map +1 -0
- package/dist/extensibility/custom-tools/types.d.ts +102 -0
- package/dist/extensibility/custom-tools/types.d.ts.map +1 -0
- package/dist/extensibility/custom-tools/types.js +5 -0
- package/dist/extensibility/custom-tools/types.js.map +1 -0
- package/dist/extensibility/index.d.ts +36 -0
- package/dist/extensibility/index.d.ts.map +1 -0
- package/dist/extensibility/index.js +79 -0
- package/dist/extensibility/index.js.map +1 -0
- package/dist/extensibility/schema.d.ts +40 -0
- package/dist/extensibility/schema.d.ts.map +1 -0
- package/dist/extensibility/schema.js +75 -0
- package/dist/extensibility/schema.js.map +1 -0
- package/dist/extensibility/validation.d.ts +11 -0
- package/dist/extensibility/validation.d.ts.map +1 -0
- package/dist/extensibility/validation.js +59 -0
- package/dist/extensibility/validation.js.map +1 -0
- package/dist/hooks/context-controller.d.ts +25 -0
- package/dist/hooks/context-controller.d.ts.map +1 -0
- package/dist/hooks/context-controller.js +21 -0
- package/dist/hooks/context-controller.js.map +1 -0
- package/dist/hooks/effects.d.ts +25 -0
- package/dist/hooks/effects.d.ts.map +1 -0
- package/dist/hooks/effects.js +45 -0
- package/dist/hooks/effects.js.map +1 -0
- package/dist/hooks/hook-messages.d.ts +10 -0
- package/dist/hooks/hook-messages.d.ts.map +1 -0
- package/dist/hooks/hook-messages.js +28 -0
- package/dist/hooks/hook-messages.js.map +1 -0
- package/dist/hooks/hook-tool-adapter.d.ts +12 -0
- package/dist/hooks/hook-tool-adapter.d.ts.map +1 -0
- package/dist/hooks/hook-tool-adapter.js +39 -0
- package/dist/hooks/hook-tool-adapter.js.map +1 -0
- package/dist/hooks/hook-transport.d.ts +19 -0
- package/dist/hooks/hook-transport.d.ts.map +1 -0
- package/dist/hooks/hook-transport.js +29 -0
- package/dist/hooks/hook-transport.js.map +1 -0
- package/dist/hooks/hook-ui-context.d.ts +20 -0
- package/dist/hooks/hook-ui-context.d.ts.map +1 -0
- package/dist/hooks/hook-ui-context.js +16 -0
- package/dist/hooks/hook-ui-context.js.map +1 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +27 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/loader.d.ts +59 -0
- package/dist/hooks/loader.d.ts.map +1 -0
- package/dist/hooks/loader.js +170 -0
- package/dist/hooks/loader.js.map +1 -0
- package/dist/hooks/message-transformer.d.ts +16 -0
- package/dist/hooks/message-transformer.d.ts.map +1 -0
- package/dist/hooks/message-transformer.js +46 -0
- package/dist/hooks/message-transformer.js.map +1 -0
- package/dist/hooks/runner.d.ts +109 -0
- package/dist/hooks/runner.d.ts.map +1 -0
- package/dist/hooks/runner.js +426 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/hooks/tool-wrapper.d.ts +16 -0
- package/dist/hooks/tool-wrapper.d.ts.map +1 -0
- package/dist/hooks/tool-wrapper.js +74 -0
- package/dist/hooks/tool-wrapper.js.map +1 -0
- package/dist/hooks/types.d.ts +431 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +8 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +56 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +13 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/lazy-tool-loader.d.ts +67 -0
- package/dist/lazy-tool-loader.d.ts.map +1 -0
- package/dist/lazy-tool-loader.js +129 -0
- package/dist/lazy-tool-loader.js.map +1 -0
- package/dist/lsp.d.ts +16 -0
- package/dist/lsp.d.ts.map +1 -0
- package/dist/lsp.js +24 -0
- package/dist/lsp.js.map +1 -0
- package/dist/runtime.d.ts +62 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +243 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session/execution-plan.d.ts +53 -0
- package/dist/session/execution-plan.d.ts.map +1 -0
- package/dist/session/execution-plan.js +170 -0
- package/dist/session/execution-plan.js.map +1 -0
- package/dist/session/orchestrator.d.ts +21 -0
- package/dist/session/orchestrator.d.ts.map +1 -0
- package/dist/session/orchestrator.js +154 -0
- package/dist/session/orchestrator.js.map +1 -0
- package/dist/session/prompt-queue.d.ts +50 -0
- package/dist/session/prompt-queue.d.ts.map +1 -0
- package/dist/session/prompt-queue.js +155 -0
- package/dist/session/prompt-queue.js.map +1 -0
- package/dist/session-manager.d.ts +80 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +257 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/tools.d.ts +10 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +19 -0
- package/dist/tools.js.map +1 -0
- package/dist/transports.d.ts +18 -0
- package/dist/transports.d.ts.map +1 -0
- package/dist/transports.js +37 -0
- package/dist/transports.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @yeshwanthyk/runtime-effect
|
|
2
|
+
|
|
3
|
+
Effect-powered runtime layer for Marvin agents (config, hooks, tools, LSP, sessions).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @yeshwanthyk/runtime-effect
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { RuntimeLayer } from "@yeshwanthyk/runtime-effect/runtime";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## License
|
|
18
|
+
|
|
19
|
+
MIT
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Agent, type AgentTransport, type ThinkingLevel } from "@yeshwanthyk/agent-core";
|
|
2
|
+
import type { Api, AgentTool, Model } from "@yeshwanthyk/ai";
|
|
3
|
+
import { Context, Layer } from "effect";
|
|
4
|
+
export interface AgentFactoryService {
|
|
5
|
+
readonly bootstrapAgent: Agent;
|
|
6
|
+
readonly createAgent: (options?: {
|
|
7
|
+
model?: Model<Api>;
|
|
8
|
+
thinking?: ThinkingLevel;
|
|
9
|
+
}) => Agent;
|
|
10
|
+
readonly transport: AgentTransport;
|
|
11
|
+
readonly tools: AgentTool[];
|
|
12
|
+
}
|
|
13
|
+
export declare const AgentFactoryTag: Context.Tag<AgentFactoryService, AgentFactoryService>;
|
|
14
|
+
export declare const AgentFactoryLayer: Layer.Layer<AgentFactoryService, Error, import("./config.js").ConfigService | import("./tools.js").ToolService | import("./transports.js").TransportService>;
|
|
15
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAKhD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,KAAK,KAAK,CAAC;IAC5F,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC;CAC7B;AAED,eAAO,MAAM,eAAe,uDAAyE,CAAC;AAEtG,eAAO,MAAM,iBAAiB,8JA0B7B,CAAC"}
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Agent } from "@yeshwanthyk/agent-core";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
import { ConfigTag } from "./config.js";
|
|
4
|
+
import { ToolServiceTag } from "./tools.js";
|
|
5
|
+
import { TransportTag } from "./transports.js";
|
|
6
|
+
export const AgentFactoryTag = Context.GenericTag("runtime-effect/AgentFactory");
|
|
7
|
+
export const AgentFactoryLayer = Layer.effect(AgentFactoryTag, Effect.gen(function* () {
|
|
8
|
+
const config = yield* ConfigTag;
|
|
9
|
+
const { transport } = yield* TransportTag;
|
|
10
|
+
const toolService = yield* ToolServiceTag;
|
|
11
|
+
const tools = yield* toolService.loadBuiltinTools();
|
|
12
|
+
const createAgent = (options) => new Agent({
|
|
13
|
+
transport: transport.router,
|
|
14
|
+
initialState: {
|
|
15
|
+
systemPrompt: config.config.systemPrompt,
|
|
16
|
+
model: options?.model ?? config.config.model,
|
|
17
|
+
thinkingLevel: options?.thinking ?? config.config.thinking,
|
|
18
|
+
tools,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
bootstrapAgent: createAgent(),
|
|
23
|
+
createAgent,
|
|
24
|
+
transport: transport.router,
|
|
25
|
+
tools,
|
|
26
|
+
};
|
|
27
|
+
}));
|
|
28
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA2C,MAAM,yBAAyB,CAAC;AAEzF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAS/C,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,CAAsB,6BAA6B,CAAC,CAAC;AAEtG,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAC,MAAM,CAC3C,eAAe,EACf,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC;IAChC,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC;IAC1C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC;IAEpD,MAAM,WAAW,GAAG,CAAC,OAA0D,EAAE,EAAE,CACjF,IAAI,KAAK,CAAC;QACR,SAAS,EAAE,SAAS,CAAC,MAAM;QAC3B,YAAY,EAAE;YACZ,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY;YACxC,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK;YAC5C,aAAa,EAAE,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ;YAC1D,KAAK;SACN;KACF,CAAC,CAAC;IAEL,OAAO;QACL,cAAc,EAAE,WAAW,EAAE;QAC7B,WAAW;QACX,SAAS,EAAE,SAAS,CAAC,MAAM;QAC3B,KAAK;KACwB,CAAC;AAClC,CAAC,CAAC,CACH,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Layer, Context } from "effect";
|
|
2
|
+
import { type Api, type KnownProvider, type Model } from "@yeshwanthyk/ai";
|
|
3
|
+
import type { ThinkingLevel } from "@yeshwanthyk/agent-core";
|
|
4
|
+
export interface AgentsConfig {
|
|
5
|
+
global?: {
|
|
6
|
+
path: string;
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
project?: {
|
|
10
|
+
path: string;
|
|
11
|
+
content: string;
|
|
12
|
+
};
|
|
13
|
+
combined: string;
|
|
14
|
+
}
|
|
15
|
+
export interface EditorConfig {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface LspConfig {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
autoInstall: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LoadedAppConfig {
|
|
24
|
+
provider: KnownProvider;
|
|
25
|
+
modelId: string;
|
|
26
|
+
model: Model<Api>;
|
|
27
|
+
thinking: ThinkingLevel;
|
|
28
|
+
theme: string;
|
|
29
|
+
editor?: EditorConfig;
|
|
30
|
+
systemPrompt: string;
|
|
31
|
+
agentsConfig: AgentsConfig;
|
|
32
|
+
configDir: string;
|
|
33
|
+
configPath: string;
|
|
34
|
+
lsp: LspConfig;
|
|
35
|
+
}
|
|
36
|
+
export declare const loadAgentsConfig: (options?: {
|
|
37
|
+
cwd?: string;
|
|
38
|
+
}) => Promise<AgentsConfig>;
|
|
39
|
+
export interface LoadConfigOptions {
|
|
40
|
+
cwd?: string;
|
|
41
|
+
configDir?: string;
|
|
42
|
+
configPath?: string;
|
|
43
|
+
provider?: string;
|
|
44
|
+
model?: string;
|
|
45
|
+
thinking?: ThinkingLevel;
|
|
46
|
+
systemPrompt?: string;
|
|
47
|
+
lsp?: LspConfig;
|
|
48
|
+
}
|
|
49
|
+
export declare const loadAppConfig: (options?: LoadConfigOptions) => Promise<LoadedAppConfig>;
|
|
50
|
+
export declare const updateAppConfig: (options: {
|
|
51
|
+
configDir?: string;
|
|
52
|
+
configPath?: string;
|
|
53
|
+
}, patch: {
|
|
54
|
+
provider?: string;
|
|
55
|
+
model?: string;
|
|
56
|
+
thinking?: ThinkingLevel;
|
|
57
|
+
theme?: string;
|
|
58
|
+
systemPrompt?: string;
|
|
59
|
+
}) => Promise<void>;
|
|
60
|
+
export interface ConfigService {
|
|
61
|
+
readonly config: LoadedAppConfig;
|
|
62
|
+
}
|
|
63
|
+
export declare const ConfigTag: Context.Tag<ConfigService, ConfigService>;
|
|
64
|
+
export declare const ConfigLayer: (options?: LoadConfigOptions) => Layer.Layer<ConfigService, import("effect/Cause").UnknownException, never>;
|
|
65
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAA2B,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACpG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAgC7D,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,eAAO,MAAM,gBAAgB,GAAU,UAAU;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,YAAY,CAmBvF,CAAC;AAgHF,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,GAAU,UAAU,iBAAiB,KAAG,OAAO,CAAC,eAAe,CAwExF,CAAC;AAOF,eAAO,MAAM,eAAe,GAC1B,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EACpD,OAAO;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5G,OAAO,CAAC,IAAI,CAed,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;CAClC;AAED,eAAO,MAAM,SAAS,2CAAoE,CAAC;AAE3F,eAAO,MAAM,WAAW,GAAI,UAAU,iBAAiB,+EAIpD,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { Effect, Layer, Context } from "effect";
|
|
5
|
+
import { getModels, getProviders } from "@yeshwanthyk/ai";
|
|
6
|
+
const GLOBAL_AGENTS_PATHS = [
|
|
7
|
+
() => path.join(os.homedir(), ".config", "marvin", "agents.md"),
|
|
8
|
+
() => path.join(os.homedir(), ".codex", "agents.md"),
|
|
9
|
+
() => path.join(os.homedir(), ".claude", "CLAUDE.md"),
|
|
10
|
+
];
|
|
11
|
+
const projectAgentsPaths = (cwd) => [
|
|
12
|
+
() => path.join(cwd, "AGENTS.md"),
|
|
13
|
+
() => path.join(cwd, "CLAUDE.md"),
|
|
14
|
+
];
|
|
15
|
+
const readFileIfExists = async (p) => {
|
|
16
|
+
try {
|
|
17
|
+
return await fs.readFile(p, "utf8");
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const loadFirstExisting = async (pathFns) => {
|
|
24
|
+
for (const pathFn of pathFns) {
|
|
25
|
+
const p = pathFn();
|
|
26
|
+
const content = await readFileIfExists(p);
|
|
27
|
+
if (content !== undefined) {
|
|
28
|
+
return { path: p, content };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
export const loadAgentsConfig = async (options) => {
|
|
34
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
35
|
+
const global = await loadFirstExisting(GLOBAL_AGENTS_PATHS);
|
|
36
|
+
const project = await loadFirstExisting(projectAgentsPaths(cwd));
|
|
37
|
+
const parts = [];
|
|
38
|
+
if (global)
|
|
39
|
+
parts.push(global.content);
|
|
40
|
+
if (project)
|
|
41
|
+
parts.push(project.content);
|
|
42
|
+
const config = {
|
|
43
|
+
combined: parts.join("\n\n---\n\n"),
|
|
44
|
+
};
|
|
45
|
+
if (global) {
|
|
46
|
+
config.global = global;
|
|
47
|
+
}
|
|
48
|
+
if (project) {
|
|
49
|
+
config.project = project;
|
|
50
|
+
}
|
|
51
|
+
return config;
|
|
52
|
+
};
|
|
53
|
+
const isThinkingLevel = (value) => value === "off" ||
|
|
54
|
+
value === "minimal" ||
|
|
55
|
+
value === "low" ||
|
|
56
|
+
value === "medium" ||
|
|
57
|
+
value === "high" ||
|
|
58
|
+
value === "xhigh";
|
|
59
|
+
const fileExists = async (p) => {
|
|
60
|
+
try {
|
|
61
|
+
await fs.stat(p);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const readJsonIfExists = async (p) => {
|
|
69
|
+
if (!(await fileExists(p)))
|
|
70
|
+
return undefined;
|
|
71
|
+
const raw = await fs.readFile(p, "utf8");
|
|
72
|
+
return JSON.parse(raw);
|
|
73
|
+
};
|
|
74
|
+
const resolveConfigDir = () => path.join(os.homedir(), ".config", "marvin");
|
|
75
|
+
const resolveProvider = (raw) => {
|
|
76
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
77
|
+
return undefined;
|
|
78
|
+
const providers = getProviders();
|
|
79
|
+
return providers.includes(raw) ? raw : undefined;
|
|
80
|
+
};
|
|
81
|
+
const resolveModel = (provider, raw) => {
|
|
82
|
+
if (typeof raw !== "string" || !raw.trim())
|
|
83
|
+
return undefined;
|
|
84
|
+
const models = getModels(provider);
|
|
85
|
+
return models.find((m) => m.id === raw);
|
|
86
|
+
};
|
|
87
|
+
const parseModelSpec = (raw) => {
|
|
88
|
+
if (typeof raw !== "string")
|
|
89
|
+
return {};
|
|
90
|
+
const first = raw
|
|
91
|
+
.split(",")
|
|
92
|
+
.map((value) => value.trim())
|
|
93
|
+
.find((value) => value.length > 0);
|
|
94
|
+
if (!first)
|
|
95
|
+
return {};
|
|
96
|
+
const slashIndex = first.indexOf("/");
|
|
97
|
+
if (slashIndex === -1) {
|
|
98
|
+
return { modelId: first };
|
|
99
|
+
}
|
|
100
|
+
const providerId = first.slice(0, slashIndex).trim();
|
|
101
|
+
const modelId = first.slice(slashIndex + 1).trim();
|
|
102
|
+
const provider = getProviders().find((p) => p === providerId);
|
|
103
|
+
const result = {};
|
|
104
|
+
if (provider)
|
|
105
|
+
result.provider = provider;
|
|
106
|
+
if (modelId.length > 0)
|
|
107
|
+
result.modelId = modelId;
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
const resolveEditorConfig = (raw) => {
|
|
111
|
+
if (typeof raw === "string") {
|
|
112
|
+
const parts = raw.trim().split(/\s+/).filter(Boolean);
|
|
113
|
+
const command = parts[0] ?? "";
|
|
114
|
+
if (!command)
|
|
115
|
+
return undefined;
|
|
116
|
+
return { command, args: parts.slice(1) };
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(raw)) {
|
|
119
|
+
const parts = raw.filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
120
|
+
const command = parts[0] ?? "";
|
|
121
|
+
if (!command)
|
|
122
|
+
return undefined;
|
|
123
|
+
return { command, args: parts.slice(1) };
|
|
124
|
+
}
|
|
125
|
+
if (typeof raw === "object" && raw !== null) {
|
|
126
|
+
const obj = raw;
|
|
127
|
+
const command = typeof obj.command === "string" ? obj.command.trim() : "";
|
|
128
|
+
if (!command)
|
|
129
|
+
return undefined;
|
|
130
|
+
const args = Array.isArray(obj.args)
|
|
131
|
+
? obj.args.filter((value) => typeof value === "string")
|
|
132
|
+
: [];
|
|
133
|
+
return { command, args };
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
};
|
|
137
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
138
|
+
const readBoolean = (value, key) => {
|
|
139
|
+
const raw = value[key];
|
|
140
|
+
return typeof raw === "boolean" ? raw : undefined;
|
|
141
|
+
};
|
|
142
|
+
const resolveLspConfig = (override, raw) => {
|
|
143
|
+
if (override) {
|
|
144
|
+
return { enabled: override.enabled, autoInstall: override.autoInstall };
|
|
145
|
+
}
|
|
146
|
+
if (raw === false) {
|
|
147
|
+
return { enabled: false, autoInstall: false };
|
|
148
|
+
}
|
|
149
|
+
if (isRecord(raw)) {
|
|
150
|
+
const enabled = readBoolean(raw, "enabled");
|
|
151
|
+
const autoInstall = readBoolean(raw, "autoInstall");
|
|
152
|
+
return { enabled: enabled ?? true, autoInstall: autoInstall ?? true };
|
|
153
|
+
}
|
|
154
|
+
return { enabled: true, autoInstall: true };
|
|
155
|
+
};
|
|
156
|
+
export const loadAppConfig = async (options) => {
|
|
157
|
+
const configDir = options?.configDir ?? resolveConfigDir();
|
|
158
|
+
const configPath = options?.configPath ?? path.join(configDir, "config.json");
|
|
159
|
+
const rawConfig = (await readJsonIfExists(configPath)) ?? {};
|
|
160
|
+
const rawObj = typeof rawConfig === "object" && rawConfig !== null ? rawConfig : {};
|
|
161
|
+
const nestedConfig = typeof rawObj.config === "object" && rawObj.config !== null ? rawObj.config : {};
|
|
162
|
+
const providerRaw = options?.provider ??
|
|
163
|
+
(typeof nestedConfig.provider === "string" ? nestedConfig.provider : undefined) ??
|
|
164
|
+
(typeof rawObj.provider === "string" ? rawObj.provider : undefined);
|
|
165
|
+
const modelSpecRaw = options?.model ??
|
|
166
|
+
(typeof nestedConfig.model === "string" ? nestedConfig.model : undefined) ??
|
|
167
|
+
(typeof rawObj.model === "string" ? rawObj.model : undefined);
|
|
168
|
+
const parsedModel = parseModelSpec(modelSpecRaw);
|
|
169
|
+
const resolvedProvider = parsedModel.provider ?? resolveProvider(providerRaw);
|
|
170
|
+
if (!resolvedProvider) {
|
|
171
|
+
throw new Error(`Invalid or missing provider. Set "provider" in ${configPath} or pass --provider. Known: ${getProviders().join(", ")}`);
|
|
172
|
+
}
|
|
173
|
+
const model = resolveModel(resolvedProvider, parsedModel.modelId);
|
|
174
|
+
if (!model) {
|
|
175
|
+
const available = getModels(resolvedProvider)
|
|
176
|
+
.slice(0, 8)
|
|
177
|
+
.map((m) => m.id)
|
|
178
|
+
.join(", ");
|
|
179
|
+
throw new Error(`Invalid or missing model for provider ${resolvedProvider}. Set "model" in ${configPath} or pass --model. Examples: ${available}`);
|
|
180
|
+
}
|
|
181
|
+
const thinkingRaw = options?.thinking ?? rawObj.thinking;
|
|
182
|
+
const thinking = isThinkingLevel(thinkingRaw) ? thinkingRaw : "off";
|
|
183
|
+
const themeRaw = rawObj.theme;
|
|
184
|
+
const theme = typeof themeRaw === "string" && themeRaw.trim() ? themeRaw.trim() : "marvin";
|
|
185
|
+
const editorRaw = typeof nestedConfig.editor !== "undefined" ? nestedConfig.editor : rawObj.editor;
|
|
186
|
+
const editor = resolveEditorConfig(editorRaw) ?? { command: "nvim", args: [] };
|
|
187
|
+
const agentsConfig = await loadAgentsConfig({ cwd: options?.cwd ?? process.cwd() });
|
|
188
|
+
const basePrompt = options?.systemPrompt ??
|
|
189
|
+
(typeof rawObj.systemPrompt === "string" && rawObj.systemPrompt.trim().length > 0
|
|
190
|
+
? rawObj.systemPrompt
|
|
191
|
+
: "You are a helpful coding agent. Use tools (read, bash, edit, write) when needed.");
|
|
192
|
+
const systemPrompt = agentsConfig.combined ? `${basePrompt}\n\n${agentsConfig.combined}` : basePrompt;
|
|
193
|
+
const lsp = resolveLspConfig(options?.lsp, rawObj.lsp);
|
|
194
|
+
return {
|
|
195
|
+
provider: resolvedProvider,
|
|
196
|
+
modelId: model.id,
|
|
197
|
+
model,
|
|
198
|
+
thinking,
|
|
199
|
+
theme,
|
|
200
|
+
editor,
|
|
201
|
+
systemPrompt,
|
|
202
|
+
agentsConfig,
|
|
203
|
+
configDir,
|
|
204
|
+
configPath,
|
|
205
|
+
lsp,
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
const writeConfigFile = async (p, value) => {
|
|
209
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
210
|
+
await fs.writeFile(p, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
211
|
+
};
|
|
212
|
+
export const updateAppConfig = async (options, patch) => {
|
|
213
|
+
const configDir = options.configDir ?? resolveConfigDir();
|
|
214
|
+
const configPath = options.configPath ?? path.join(configDir, "config.json");
|
|
215
|
+
const existing = (await readJsonIfExists(configPath)) ?? {};
|
|
216
|
+
const existingObj = typeof existing === "object" && existing !== null ? existing : {};
|
|
217
|
+
const next = { ...existingObj };
|
|
218
|
+
if (patch.provider)
|
|
219
|
+
next.provider = patch.provider;
|
|
220
|
+
if (patch.model)
|
|
221
|
+
next.model = patch.model;
|
|
222
|
+
if (patch.thinking)
|
|
223
|
+
next.thinking = patch.thinking;
|
|
224
|
+
if (patch.theme)
|
|
225
|
+
next.theme = patch.theme;
|
|
226
|
+
if (patch.systemPrompt)
|
|
227
|
+
next.systemPrompt = patch.systemPrompt;
|
|
228
|
+
await writeConfigFile(configPath, next);
|
|
229
|
+
};
|
|
230
|
+
export const ConfigTag = Context.GenericTag("runtime-effect/ConfigService");
|
|
231
|
+
export const ConfigLayer = (options) => Layer.effect(ConfigTag, Effect.tryPromise(() => loadAppConfig(options)).pipe(Effect.map((config) => ({ config }))));
|
|
232
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,YAAY,EAA4C,MAAM,iBAAiB,CAAC;AAGpG,MAAM,mBAAmB,GAAG;IAC1B,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC;IAC/D,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC;IACpD,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC;CACtD,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC;IAC1C,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;IACjC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;CAClC,CAAC;AAEF,MAAM,gBAAgB,GAAG,KAAK,EAAE,CAAS,EAA+B,EAAE;IACxE,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAA4B,EAA0D,EAAE;IACvH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAgCF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,OAA0B,EAAyB,EAAE;IAC1F,MAAM,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;IAEjE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAiB;QAC3B,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC;KACpC,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,KAAc,EAA0B,EAAE,CACjE,KAAK,KAAK,KAAK;IACf,KAAK,KAAK,SAAS;IACnB,KAAK,KAAK,KAAK;IACf,KAAK,KAAK,QAAQ;IAClB,KAAK,KAAK,MAAM;IAChB,KAAK,KAAK,OAAO,CAAC;AAEpB,MAAM,UAAU,GAAG,KAAK,EAAE,CAAS,EAAoB,EAAE;IACvD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,KAAK,EAAE,CAAS,EAAgC,EAAE;IACzE,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEpF,MAAM,eAAe,GAAG,CAAC,GAAY,EAA6B,EAAE;IAClE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,OAAO,SAAS,CAAC,QAAQ,CAAC,GAAoB,CAAC,CAAC,CAAC,CAAE,GAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;AACvF,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,QAAuB,EAAE,GAAY,EAA0B,EAAE;IACrF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAA2B,CAAC;AACpE,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,GAAY,EAAkD,EAAE;IACtF,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,GAAG;SACd,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAmD,EAAE,CAAC;IAClE,IAAI,QAAQ;QAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACzC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IACjD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,GAAY,EAA4B,EAAE;IACrE,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3G,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,GAAG,GAAG,GAA8B,CAAC;QAC3C,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAClC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;YACxE,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AAEnH,MAAM,WAAW,GAAG,CAAC,KAA8B,EAAE,GAAW,EAAuB,EAAE;IACvF,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,OAAO,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,QAA+B,EAAE,GAAY,EAAa,EAAE;IACpF,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QACpD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,WAAW,EAAE,WAAW,IAAI,IAAI,EAAE,CAAC;IACxE,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC,CAAC;AAaF,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,OAA2B,EAA4B,EAAE;IAC3F,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC3D,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAE9E,MAAM,SAAS,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAE7D,MAAM,MAAM,GAAG,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAE,SAAqC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjH,MAAM,YAAY,GAChB,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAE,MAAM,CAAC,MAAkC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEhH,MAAM,WAAW,GACf,OAAO,EAAE,QAAQ;QACjB,CAAC,OAAO,YAAY,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAEtE,MAAM,YAAY,GAChB,OAAO,EAAE,KAAK;QACd,CAAC,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,gBAAgB,GAAG,WAAW,CAAC,QAAQ,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;IAC9E,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,kDAAkD,UAAU,+BAA+B,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvH,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,gBAAgB,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,SAAS,CAAC,gBAAgB,CAAC;aAC1C,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChB,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CACb,yCAAyC,gBAAgB,oBAAoB,UAAU,+BAA+B,SAAS,EAAE,CAClI,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;IACzD,MAAM,QAAQ,GAAkB,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;IAEnF,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE3F,MAAM,SAAS,GAAG,OAAO,YAAY,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IACnG,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAE/E,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAEpF,MAAM,UAAU,GACd,OAAO,EAAE,YAAY;QACrB,CAAC,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC/E,CAAC,CAAC,MAAM,CAAC,YAAY;YACrB,CAAC,CAAC,kFAAkF,CAAC,CAAC;IAE1F,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;IAEtG,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAEvD,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,KAAK;QACL,QAAQ;QACR,KAAK;QACL,MAAM;QACN,YAAY;QACZ,YAAY;QACZ,SAAS;QACT,UAAU;QACV,GAAG;KACJ,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,KAAK,EAAE,CAAS,EAAE,KAA8B,EAAiB,EAAE;IACzF,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AACvE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,OAAoD,EACpD,KAA6G,EAC9F,EAAE;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAE7E,MAAM,QAAQ,GAAG,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,WAAW,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAE,QAAoC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnH,MAAM,IAAI,GAA4B,EAAE,GAAG,WAAW,EAAE,CAAC;IACzD,IAAI,KAAK,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnD,IAAI,KAAK,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnD,IAAI,KAAK,CAAC,KAAK;QAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,YAAY;QAAE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAE/D,MAAM,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAgB,8BAA8B,CAAC,CAAC;AAE3F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAA2B,EAAE,EAAE,CACzD,KAAK,CAAC,MAAM,CACV,SAAS,EACT,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAC3F,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom slash command loader
|
|
3
|
+
*
|
|
4
|
+
* Loads markdown templates from ~/.config/marvin/commands/*.md
|
|
5
|
+
* Commands are expanded with $ARGUMENTS placeholder or appended args.
|
|
6
|
+
*/
|
|
7
|
+
import { Context, Layer } from "effect";
|
|
8
|
+
import type { ValidationIssue } from "./schema.js";
|
|
9
|
+
export interface CustomCommand {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
template: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CustomCommandLoadResult {
|
|
15
|
+
commands: Map<string, CustomCommand>;
|
|
16
|
+
issues: ValidationIssue[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Load custom commands from a config directory.
|
|
20
|
+
* @param configDir - Base config directory (e.g., ~/.config/marvin)
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadCustomCommands(configDir: string): CustomCommandLoadResult;
|
|
23
|
+
/**
|
|
24
|
+
* Expand a custom command template with arguments.
|
|
25
|
+
*
|
|
26
|
+
* - Replaces $ARGUMENTS with the raw args string
|
|
27
|
+
* - If no $ARGUMENTS placeholder and args exist, appends args after two newlines
|
|
28
|
+
*
|
|
29
|
+
* @param template - The command template
|
|
30
|
+
* @param args - Raw argument string (everything after the command name)
|
|
31
|
+
* @returns Expanded prompt text
|
|
32
|
+
*/
|
|
33
|
+
export declare function expandCommand(template: string, args: string): string;
|
|
34
|
+
export interface CustomCommandService extends CustomCommandLoadResult {
|
|
35
|
+
}
|
|
36
|
+
export declare const CustomCommandTag: Context.Tag<CustomCommandService, CustomCommandService>;
|
|
37
|
+
export interface CustomCommandLayerOptions {
|
|
38
|
+
configDir?: string;
|
|
39
|
+
loader?: (configDir: string) => CustomCommandLoadResult;
|
|
40
|
+
}
|
|
41
|
+
export declare const CustomCommandLayer: (options?: CustomCommandLayerOptions) => Layer.Layer<CustomCommandService, never, import("../config.js").ConfigService | import("../instrumentation.js").InstrumentationService>;
|
|
42
|
+
/**
|
|
43
|
+
* Try to expand a slash command input.
|
|
44
|
+
*
|
|
45
|
+
* @param input - Raw input starting with /
|
|
46
|
+
* @param builtInNames - Set of built-in command names (to avoid shadowing)
|
|
47
|
+
* @param customCommands - Map of custom commands
|
|
48
|
+
* @returns Expanded text if matched, or null if not a custom command
|
|
49
|
+
*/
|
|
50
|
+
export declare function tryExpandCustomCommand(input: string, builtInNames: Set<string>, customCommands: Map<string, CustomCommand>): string | null;
|
|
51
|
+
//# sourceMappingURL=custom-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-commands.d.ts","sourceRoot":"","sources":["../../src/extensibility/custom-commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAKlD,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;CAChB;AAYD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IACpC,MAAM,EAAE,eAAe,EAAE,CAAA;CACzB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,uBAAuB,CA4D7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAYpE;AAED,MAAM,WAAW,oBAAqB,SAAQ,uBAAuB;CAAG;AAExE,eAAO,MAAM,gBAAgB,yDAAkF,CAAA;AAE/G,MAAM,WAAW,yBAAyB;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,uBAAuB,CAAA;CACvD;AAED,eAAO,MAAM,kBAAkB,GAAI,UAAU,yBAAyB,4IAwBpE,CAAA;AAEF;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GACxC,MAAM,GAAG,IAAI,CAiBf"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom slash command loader
|
|
3
|
+
*
|
|
4
|
+
* Loads markdown templates from ~/.config/marvin/commands/*.md
|
|
5
|
+
* Commands are expanded with $ARGUMENTS placeholder or appended args.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { Context, Effect, Layer } from "effect";
|
|
10
|
+
import { validateCustomCommand, issueFromError } from "./validation.js";
|
|
11
|
+
import { ConfigTag } from "../config.js";
|
|
12
|
+
import { InstrumentationTag } from "../instrumentation.js";
|
|
13
|
+
/** Valid command name: alphanumeric, starting with letter/digit, allowing _ and - */
|
|
14
|
+
const VALID_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
15
|
+
const createInvalidNameIssue = (path, message) => ({
|
|
16
|
+
kind: "command",
|
|
17
|
+
severity: "error",
|
|
18
|
+
path,
|
|
19
|
+
message,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Load custom commands from a config directory.
|
|
23
|
+
* @param configDir - Base config directory (e.g., ~/.config/marvin)
|
|
24
|
+
*/
|
|
25
|
+
export function loadCustomCommands(configDir) {
|
|
26
|
+
const commands = new Map();
|
|
27
|
+
const issues = [];
|
|
28
|
+
const commandsDir = join(configDir, "commands");
|
|
29
|
+
if (!existsSync(commandsDir)) {
|
|
30
|
+
return { commands, issues };
|
|
31
|
+
}
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = readdirSync(commandsDir);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
issues.push(issueFromError("command", commandsDir, error));
|
|
38
|
+
return { commands, issues };
|
|
39
|
+
}
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
if (!entry.endsWith(".md"))
|
|
42
|
+
continue;
|
|
43
|
+
const name = entry.slice(0, -3); // Remove .md extension
|
|
44
|
+
const filePath = join(commandsDir, entry);
|
|
45
|
+
if (!VALID_NAME_PATTERN.test(name)) {
|
|
46
|
+
issues.push(createInvalidNameIssue(filePath, `Invalid command name "${name}". Use letters, numbers, _ or -.`));
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
let content;
|
|
50
|
+
try {
|
|
51
|
+
content = readFileSync(filePath, "utf-8");
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
issues.push(issueFromError("command", filePath, error));
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Extract description from first non-empty line, truncated to 60 chars
|
|
58
|
+
const lines = content.split("\n");
|
|
59
|
+
let description = `/${name}`;
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const trimmed = line.trim();
|
|
62
|
+
if (trimmed) {
|
|
63
|
+
description = trimmed.length > 60 ? trimmed.slice(0, 57) + "..." : trimmed;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const manifest = {
|
|
68
|
+
name,
|
|
69
|
+
description,
|
|
70
|
+
template: content,
|
|
71
|
+
};
|
|
72
|
+
issues.push(...validateCustomCommand(manifest, filePath));
|
|
73
|
+
commands.set(name, manifest);
|
|
74
|
+
}
|
|
75
|
+
return { commands, issues };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Expand a custom command template with arguments.
|
|
79
|
+
*
|
|
80
|
+
* - Replaces $ARGUMENTS with the raw args string
|
|
81
|
+
* - If no $ARGUMENTS placeholder and args exist, appends args after two newlines
|
|
82
|
+
*
|
|
83
|
+
* @param template - The command template
|
|
84
|
+
* @param args - Raw argument string (everything after the command name)
|
|
85
|
+
* @returns Expanded prompt text
|
|
86
|
+
*/
|
|
87
|
+
export function expandCommand(template, args) {
|
|
88
|
+
const trimmedArgs = args.trim();
|
|
89
|
+
if (template.includes("$ARGUMENTS")) {
|
|
90
|
+
return template.replace(/\$ARGUMENTS/g, trimmedArgs);
|
|
91
|
+
}
|
|
92
|
+
if (trimmedArgs) {
|
|
93
|
+
return `${template}\n\n${trimmedArgs}`;
|
|
94
|
+
}
|
|
95
|
+
return template;
|
|
96
|
+
}
|
|
97
|
+
export const CustomCommandTag = Context.GenericTag("runtime-effect/CustomCommandService");
|
|
98
|
+
export const CustomCommandLayer = (options) => Layer.effect(CustomCommandTag, Effect.gen(function* () {
|
|
99
|
+
const configDir = options?.configDir ??
|
|
100
|
+
(yield* ConfigTag).config.configDir;
|
|
101
|
+
const instrumentation = yield* InstrumentationTag;
|
|
102
|
+
const loader = options?.loader ?? loadCustomCommands;
|
|
103
|
+
const result = yield* Effect.sync(() => loader(configDir));
|
|
104
|
+
for (const issue of result.issues) {
|
|
105
|
+
instrumentation.record({ type: "extensibility:validation-issue", issue });
|
|
106
|
+
}
|
|
107
|
+
instrumentation.record({
|
|
108
|
+
type: "extensibility:commands-loaded",
|
|
109
|
+
count: result.commands.size,
|
|
110
|
+
names: Array.from(result.commands.keys()),
|
|
111
|
+
});
|
|
112
|
+
return result;
|
|
113
|
+
}));
|
|
114
|
+
/**
|
|
115
|
+
* Try to expand a slash command input.
|
|
116
|
+
*
|
|
117
|
+
* @param input - Raw input starting with /
|
|
118
|
+
* @param builtInNames - Set of built-in command names (to avoid shadowing)
|
|
119
|
+
* @param customCommands - Map of custom commands
|
|
120
|
+
* @returns Expanded text if matched, or null if not a custom command
|
|
121
|
+
*/
|
|
122
|
+
export function tryExpandCustomCommand(input, builtInNames, customCommands) {
|
|
123
|
+
const trimmed = input.trim();
|
|
124
|
+
if (!trimmed.startsWith("/"))
|
|
125
|
+
return null;
|
|
126
|
+
// Parse command name and args
|
|
127
|
+
const withoutSlash = trimmed.slice(1);
|
|
128
|
+
const spaceIdx = withoutSlash.indexOf(" ");
|
|
129
|
+
const commandName = spaceIdx === -1 ? withoutSlash : withoutSlash.slice(0, spaceIdx);
|
|
130
|
+
const args = spaceIdx === -1 ? "" : withoutSlash.slice(spaceIdx + 1);
|
|
131
|
+
// Built-ins take precedence (no override in v1)
|
|
132
|
+
if (builtInNames.has(commandName))
|
|
133
|
+
return null;
|
|
134
|
+
const cmd = customCommands.get(commandName);
|
|
135
|
+
if (!cmd)
|
|
136
|
+
return null;
|
|
137
|
+
return expandCommand(cmd.template, args);
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=custom-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-commands.js","sourceRoot":"","sources":["../../src/extensibility/custom-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom tools module exports.
|
|
3
|
+
*/
|
|
4
|
+
export { loadCustomTools } from "./loader.js";
|
|
5
|
+
export type { CustomAgentTool, CustomToolFactory, CustomToolsLoadResult, ExecOptions, ExecResult, LoadedCustomTool, RenderResultOptions, SendRef, SessionEvent, ToolAPI, } from "./types.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensibility/custom-tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EACX,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,mBAAmB,EACnB,OAAO,EACP,YAAY,EACZ,OAAO,GACP,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensibility/custom-tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom tool loader - discovers and loads TypeScript tool modules.
|
|
3
|
+
*
|
|
4
|
+
* Tools are loaded from:
|
|
5
|
+
* - ~/.config/marvin/tools/*.ts (single-file tools)
|
|
6
|
+
* - ~/.config/marvin/tools/<name>/index.ts (directory-based tools)
|
|
7
|
+
*
|
|
8
|
+
* Uses Bun's native import() which handles TypeScript directly.
|
|
9
|
+
*/
|
|
10
|
+
import type { CustomToolsLoadResult, SendRef } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Discover and load tools from the config directory.
|
|
13
|
+
* Loads from ~/.config/marvin/tools/*.ts
|
|
14
|
+
*
|
|
15
|
+
* @param configDir - Base config directory (e.g., ~/.config/marvin)
|
|
16
|
+
* @param cwd - Current working directory for tool execution
|
|
17
|
+
* @param builtInToolNames - Names of built-in tools to check for conflicts
|
|
18
|
+
* @param sendRef - Ref for send handler (set by App after initialization)
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadCustomTools(configDir: string, cwd: string, builtInToolNames: string[], sendRef: SendRef, hasUI: boolean): Promise<CustomToolsLoadResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Get built-in tool names from an array of tools.
|
|
23
|
+
*/
|
|
24
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/extensibility/custom-tools/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAEX,qBAAqB,EAIrB,OAAO,EAEP,MAAM,YAAY,CAAA;AAyKnB;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACpC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,gBAAgB,EAAE,MAAM,EAAE,EAC1B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,OAAO,GACZ,OAAO,CAAC,qBAAqB,CAAC,CAgEhC;AAED;;GAEG"}
|