@bytesbrains/opencode-cruise 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/LICENSE +15 -0
- package/README.md +189 -0
- package/dist/auth.d.ts +7 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +44 -0
- package/dist/auth.js.map +1 -0
- package/dist/base-url.d.ts +8 -0
- package/dist/base-url.d.ts.map +1 -0
- package/dist/base-url.js +30 -0
- package/dist/base-url.js.map +1 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +20 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/fetch-models.d.ts +23 -0
- package/dist/fetch-models.d.ts.map +1 -0
- package/dist/fetch-models.js +61 -0
- package/dist/fetch-models.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-client.d.ts +27 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +95 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp-url.d.ts +6 -0
- package/dist/mcp-url.d.ts.map +1 -0
- package/dist/mcp-url.js +22 -0
- package/dist/mcp-url.js.map +1 -0
- package/dist/models.d.ts +42 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +132 -0
- package/dist/models.js.map +1 -0
- package/dist/provider.d.ts +22 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +68 -0
- package/dist/provider.js.map +1 -0
- package/dist/resolve-api-key.d.ts +15 -0
- package/dist/resolve-api-key.d.ts.map +1 -0
- package/dist/resolve-api-key.js +43 -0
- package/dist/resolve-api-key.js.map +1 -0
- package/dist/tools.d.ts +124 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +231 -0
- package/dist/tools.js.map +1 -0
- package/package.json +60 -0
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Config } from "@opencode-ai/plugin";
|
|
2
|
+
import type { ResolveCruiseApiKeyOptions } from "./resolve-api-key.js";
|
|
3
|
+
export type CruiseToolsContext = {
|
|
4
|
+
env?: Record<string, string | undefined>;
|
|
5
|
+
stateDir?: string;
|
|
6
|
+
resolveKey?: (options?: ResolveCruiseApiKeyOptions) => Promise<string | undefined>;
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
8
|
+
/** Injectable for tests — defaults to reading/writing opencode.json under directory. */
|
|
9
|
+
readConfigFile?: (path: string) => Promise<string>;
|
|
10
|
+
writeConfigFile?: (path: string, contents: string) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Inject Cruise as a remote OpenCode MCP server when the user has not already
|
|
14
|
+
* configured `mcp.cruise`. Key stays in the environment via `{env:…}`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function applyCruiseMcp(config: Config, options?: {
|
|
17
|
+
mcpUrl: string;
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
}): {
|
|
20
|
+
applied: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** Default tool map for the plugin (uses process env + auth store). */
|
|
23
|
+
export declare const cruiseTools: {
|
|
24
|
+
cruise_list_models: {
|
|
25
|
+
description: string;
|
|
26
|
+
args: {
|
|
27
|
+
kind: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
28
|
+
models: "models";
|
|
29
|
+
all: "all";
|
|
30
|
+
lanes: "lanes";
|
|
31
|
+
}>>;
|
|
32
|
+
modality: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
33
|
+
image: "image";
|
|
34
|
+
chat: "chat";
|
|
35
|
+
speech: "speech";
|
|
36
|
+
embedding: "embedding";
|
|
37
|
+
}>>;
|
|
38
|
+
};
|
|
39
|
+
execute(args: {
|
|
40
|
+
kind?: "models" | "all" | "lanes" | undefined;
|
|
41
|
+
modality?: "image" | "chat" | "speech" | "embedding" | undefined;
|
|
42
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
43
|
+
};
|
|
44
|
+
cruise_get_budget: {
|
|
45
|
+
description: string;
|
|
46
|
+
args: {};
|
|
47
|
+
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
48
|
+
};
|
|
49
|
+
cruise_get_spend: {
|
|
50
|
+
description: string;
|
|
51
|
+
args: {
|
|
52
|
+
month: import("zod").ZodOptional<import("zod").ZodString>;
|
|
53
|
+
by: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
54
|
+
model: "model";
|
|
55
|
+
lane: "lane";
|
|
56
|
+
}>>;
|
|
57
|
+
};
|
|
58
|
+
execute(args: {
|
|
59
|
+
month?: string | undefined;
|
|
60
|
+
by?: "model" | "lane" | undefined;
|
|
61
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
62
|
+
};
|
|
63
|
+
cruise_setup: {
|
|
64
|
+
description: string;
|
|
65
|
+
args: {
|
|
66
|
+
write_config: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
67
|
+
};
|
|
68
|
+
execute(args: {
|
|
69
|
+
write_config?: boolean | undefined;
|
|
70
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/** Test seam: build tools with injectable env / fetch / filesystem. */
|
|
74
|
+
export declare function createCruiseTools(ctx: CruiseToolsContext): {
|
|
75
|
+
cruise_list_models: {
|
|
76
|
+
description: string;
|
|
77
|
+
args: {
|
|
78
|
+
kind: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
79
|
+
models: "models";
|
|
80
|
+
all: "all";
|
|
81
|
+
lanes: "lanes";
|
|
82
|
+
}>>;
|
|
83
|
+
modality: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
84
|
+
image: "image";
|
|
85
|
+
chat: "chat";
|
|
86
|
+
speech: "speech";
|
|
87
|
+
embedding: "embedding";
|
|
88
|
+
}>>;
|
|
89
|
+
};
|
|
90
|
+
execute(args: {
|
|
91
|
+
kind?: "models" | "all" | "lanes" | undefined;
|
|
92
|
+
modality?: "image" | "chat" | "speech" | "embedding" | undefined;
|
|
93
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
94
|
+
};
|
|
95
|
+
cruise_get_budget: {
|
|
96
|
+
description: string;
|
|
97
|
+
args: {};
|
|
98
|
+
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
99
|
+
};
|
|
100
|
+
cruise_get_spend: {
|
|
101
|
+
description: string;
|
|
102
|
+
args: {
|
|
103
|
+
month: import("zod").ZodOptional<import("zod").ZodString>;
|
|
104
|
+
by: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
105
|
+
model: "model";
|
|
106
|
+
lane: "lane";
|
|
107
|
+
}>>;
|
|
108
|
+
};
|
|
109
|
+
execute(args: {
|
|
110
|
+
month?: string | undefined;
|
|
111
|
+
by?: "model" | "lane" | undefined;
|
|
112
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
113
|
+
};
|
|
114
|
+
cruise_setup: {
|
|
115
|
+
description: string;
|
|
116
|
+
args: {
|
|
117
|
+
write_config: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
118
|
+
};
|
|
119
|
+
execute(args: {
|
|
120
|
+
write_config?: boolean | undefined;
|
|
121
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAWlD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAGvE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,0BAA0B,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACnF,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,wFAAwF;IACxF,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE,CAAC;AAmBF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAE3C,GACA;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAgBtB;AAwMD,uEAAuE;AACvE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAqB,CAAC;AAE9C,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAExD"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { tool } from "@opencode-ai/plugin";
|
|
4
|
+
import { resolveAllowedCruiseBaseUrl } from "./base-url.js";
|
|
5
|
+
import { CRUISE_API_KEY_ENV, CRUISE_BASE_URL, CRUISE_BASE_URL_ENV, PROVIDER_ID, } from "./constants.js";
|
|
6
|
+
import { callCruiseMcpTool } from "./mcp-client.js";
|
|
7
|
+
import { resolveCruiseMcpUrl } from "./mcp-url.js";
|
|
8
|
+
import { resolveCruiseApiKey } from "./resolve-api-key.js";
|
|
9
|
+
function asRecord(value) {
|
|
10
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
11
|
+
? value
|
|
12
|
+
: {};
|
|
13
|
+
}
|
|
14
|
+
async function resolveWire(ctx) {
|
|
15
|
+
const env = ctx.env ?? process.env;
|
|
16
|
+
const resolveKey = ctx.resolveKey ?? resolveCruiseApiKey;
|
|
17
|
+
const apiKey = await resolveKey({ env, stateDir: ctx.stateDir });
|
|
18
|
+
const baseUrl = resolveAllowedCruiseBaseUrl(typeof env[CRUISE_BASE_URL_ENV] === "string" ? env[CRUISE_BASE_URL_ENV] : CRUISE_BASE_URL);
|
|
19
|
+
const mcpUrl = resolveCruiseMcpUrl(baseUrl);
|
|
20
|
+
return { apiKey, baseUrl, mcpUrl, env };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Inject Cruise as a remote OpenCode MCP server when the user has not already
|
|
24
|
+
* configured `mcp.cruise`. Key stays in the environment via `{env:…}`.
|
|
25
|
+
*/
|
|
26
|
+
export function applyCruiseMcp(config, options = {
|
|
27
|
+
mcpUrl: resolveCruiseMcpUrl(),
|
|
28
|
+
}) {
|
|
29
|
+
config.mcp ??= {};
|
|
30
|
+
const existing = config.mcp[PROVIDER_ID];
|
|
31
|
+
if (existing !== undefined) {
|
|
32
|
+
return { applied: false };
|
|
33
|
+
}
|
|
34
|
+
config.mcp[PROVIDER_ID] = {
|
|
35
|
+
type: "remote",
|
|
36
|
+
url: options.mcpUrl,
|
|
37
|
+
enabled: options.enabled ?? true,
|
|
38
|
+
oauth: false,
|
|
39
|
+
headers: {
|
|
40
|
+
Authorization: `Bearer {env:${CRUISE_API_KEY_ENV}}`,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return { applied: true };
|
|
44
|
+
}
|
|
45
|
+
function buildCruiseTools(ctx = {}) {
|
|
46
|
+
return {
|
|
47
|
+
cruise_list_models: tool({
|
|
48
|
+
description: "List models and lanes this Cruise key can reach, with capabilities and list prices (USD per million tokens). Use a lane id such as bb/agentic-coding as the model name.",
|
|
49
|
+
args: {
|
|
50
|
+
kind: tool.schema
|
|
51
|
+
.enum(["all", "lanes", "models"])
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Lanes only, pinned models only, or both. Default all."),
|
|
54
|
+
modality: tool.schema
|
|
55
|
+
.enum(["chat", "image", "speech", "embedding"])
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Only entries of this modality."),
|
|
58
|
+
},
|
|
59
|
+
async execute(args) {
|
|
60
|
+
const wire = await resolveWire(ctx);
|
|
61
|
+
if (!wire.apiKey) {
|
|
62
|
+
return `Set ${CRUISE_API_KEY_ENV} (or /connect Cruise API Key). Never put the key in opencode.json.`;
|
|
63
|
+
}
|
|
64
|
+
const arguments_ = {};
|
|
65
|
+
if (args.kind)
|
|
66
|
+
arguments_.kind = args.kind;
|
|
67
|
+
if (args.modality)
|
|
68
|
+
arguments_.modality = args.modality;
|
|
69
|
+
const result = await callCruiseMcpTool({
|
|
70
|
+
mcpUrl: wire.mcpUrl,
|
|
71
|
+
apiKey: wire.apiKey,
|
|
72
|
+
name: "list_models",
|
|
73
|
+
arguments: arguments_,
|
|
74
|
+
fetchImpl: ctx.fetchImpl,
|
|
75
|
+
});
|
|
76
|
+
return result.ok ? result.text : result.reason;
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
cruise_get_budget: tool({
|
|
80
|
+
description: "This Cruise key's project budget for the current period, caps, action (serve/refuse), and the tenant wallet. Read-only.",
|
|
81
|
+
args: {},
|
|
82
|
+
async execute() {
|
|
83
|
+
const wire = await resolveWire(ctx);
|
|
84
|
+
if (!wire.apiKey) {
|
|
85
|
+
return `Set ${CRUISE_API_KEY_ENV} (or /connect Cruise API Key). Never put the key in opencode.json.`;
|
|
86
|
+
}
|
|
87
|
+
const result = await callCruiseMcpTool({
|
|
88
|
+
mcpUrl: wire.mcpUrl,
|
|
89
|
+
apiKey: wire.apiKey,
|
|
90
|
+
name: "get_budget",
|
|
91
|
+
fetchImpl: ctx.fetchImpl,
|
|
92
|
+
});
|
|
93
|
+
return result.ok ? result.text : result.reason;
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
cruise_get_spend: tool({
|
|
97
|
+
description: "What this Cruise key's project was charged in a calendar month, grouped by model or lane. Read-only.",
|
|
98
|
+
args: {
|
|
99
|
+
month: tool.schema
|
|
100
|
+
.string()
|
|
101
|
+
.regex(/^\d{4}-(0[1-9]|1[0-2])$/)
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("YYYY-MM. Default: current month (UTC)."),
|
|
104
|
+
by: tool.schema
|
|
105
|
+
.enum(["model", "lane"])
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Group by served model or requested lane. Default model."),
|
|
108
|
+
},
|
|
109
|
+
async execute(args) {
|
|
110
|
+
const wire = await resolveWire(ctx);
|
|
111
|
+
if (!wire.apiKey) {
|
|
112
|
+
return `Set ${CRUISE_API_KEY_ENV} (or /connect Cruise API Key). Never put the key in opencode.json.`;
|
|
113
|
+
}
|
|
114
|
+
const arguments_ = {};
|
|
115
|
+
if (args.month)
|
|
116
|
+
arguments_.month = args.month;
|
|
117
|
+
if (args.by)
|
|
118
|
+
arguments_.by = args.by;
|
|
119
|
+
const result = await callCruiseMcpTool({
|
|
120
|
+
mcpUrl: wire.mcpUrl,
|
|
121
|
+
apiKey: wire.apiKey,
|
|
122
|
+
name: "get_spend",
|
|
123
|
+
arguments: arguments_,
|
|
124
|
+
fetchImpl: ctx.fetchImpl,
|
|
125
|
+
});
|
|
126
|
+
return result.ok ? result.text : result.reason;
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
cruise_setup: tool({
|
|
130
|
+
description: "Check the Cruise key (without revealing it), probe get_budget over MCP, and optionally write mcp.cruise into opencode.json with consent. The key stays in the environment.",
|
|
131
|
+
args: {
|
|
132
|
+
write_config: tool.schema
|
|
133
|
+
.boolean()
|
|
134
|
+
.optional()
|
|
135
|
+
.describe("If true, merge mcp.cruise into ./opencode.json after asking for permission. Default false (probe only)."),
|
|
136
|
+
},
|
|
137
|
+
async execute(args, toolCtx) {
|
|
138
|
+
const wire = await resolveWire(ctx);
|
|
139
|
+
const lines = [];
|
|
140
|
+
lines.push(`MCP URL: ${wire.mcpUrl}`);
|
|
141
|
+
lines.push(wire.apiKey
|
|
142
|
+
? `${CRUISE_API_KEY_ENV}: set (value not shown)`
|
|
143
|
+
: `${CRUISE_API_KEY_ENV}: missing — export a cru_… key or use /connect`);
|
|
144
|
+
if (!wire.apiKey) {
|
|
145
|
+
return lines.join("\n");
|
|
146
|
+
}
|
|
147
|
+
const probe = await callCruiseMcpTool({
|
|
148
|
+
mcpUrl: wire.mcpUrl,
|
|
149
|
+
apiKey: wire.apiKey,
|
|
150
|
+
name: "get_budget",
|
|
151
|
+
fetchImpl: ctx.fetchImpl,
|
|
152
|
+
});
|
|
153
|
+
if (!probe.ok) {
|
|
154
|
+
lines.push(`get_budget: failed — ${probe.reason}`);
|
|
155
|
+
return lines.join("\n");
|
|
156
|
+
}
|
|
157
|
+
lines.push("get_budget: ok");
|
|
158
|
+
lines.push(probe.text);
|
|
159
|
+
if (!args.write_config) {
|
|
160
|
+
lines.push("Config not written. Re-run with write_config=true to merge mcp.cruise into opencode.json (asks first; key stays in env).");
|
|
161
|
+
return lines.join("\n");
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
await toolCtx.ask({
|
|
165
|
+
permission: "edit",
|
|
166
|
+
patterns: ["opencode.json"],
|
|
167
|
+
always: ["opencode.json"],
|
|
168
|
+
metadata: {
|
|
169
|
+
reason: "Merge BytesBrains Cruise MCP (mcp.cruise) — Authorization uses {env:CRUISE_API_KEY}",
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
lines.push("Write cancelled — permission not granted.");
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
}
|
|
177
|
+
const configPath = join(toolCtx.directory, "opencode.json");
|
|
178
|
+
const read = ctx.readConfigFile ?? ((path) => readFile(path, "utf8"));
|
|
179
|
+
const write = ctx.writeConfigFile ?? ((path, contents) => writeFile(path, contents, "utf8"));
|
|
180
|
+
let parsed = {
|
|
181
|
+
$schema: "https://opencode.ai/config.json",
|
|
182
|
+
};
|
|
183
|
+
try {
|
|
184
|
+
const raw = await read(configPath);
|
|
185
|
+
const json = JSON.parse(raw);
|
|
186
|
+
parsed = asRecord(json);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* create fresh */
|
|
190
|
+
}
|
|
191
|
+
const mcp = asRecord(parsed.mcp);
|
|
192
|
+
if (mcp[PROVIDER_ID] !== undefined) {
|
|
193
|
+
lines.push("opencode.json already has mcp.cruise — left unchanged.");
|
|
194
|
+
return lines.join("\n");
|
|
195
|
+
}
|
|
196
|
+
parsed.mcp = {
|
|
197
|
+
...mcp,
|
|
198
|
+
[PROVIDER_ID]: {
|
|
199
|
+
type: "remote",
|
|
200
|
+
url: wire.mcpUrl,
|
|
201
|
+
enabled: true,
|
|
202
|
+
oauth: false,
|
|
203
|
+
headers: {
|
|
204
|
+
Authorization: `Bearer {env:${CRUISE_API_KEY_ENV}}`,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
if (!parsed.$schema) {
|
|
209
|
+
parsed.$schema = "https://opencode.ai/config.json";
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
await write(configPath, `${JSON.stringify(parsed, null, 2)}\n`);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
216
|
+
lines.push(`Could not write mcp.cruise into ${configPath}: ${message}`);
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
lines.push(`Wrote mcp.cruise into ${configPath} (key still only in ${CRUISE_API_KEY_ENV}).`);
|
|
220
|
+
return lines.join("\n");
|
|
221
|
+
},
|
|
222
|
+
}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/** Default tool map for the plugin (uses process env + auth store). */
|
|
226
|
+
export const cruiseTools = buildCruiseTools();
|
|
227
|
+
/** Test seam: build tools with injectable env / fetch / filesystem. */
|
|
228
|
+
export function createCruiseTools(ctx) {
|
|
229
|
+
return buildCruiseTools(ctx);
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAY3D,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAChE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAuB;IAChD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACnC,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,mBAAmB,CAAC;IACzD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,2BAA2B,CACzC,OAAO,GAAG,CAAC,mBAAmB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,eAAe,CAC1F,CAAC;IACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,UAAiD;IAC/C,MAAM,EAAE,mBAAmB,EAAE;CAC9B;IAED,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;IAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG;QACxB,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,OAAO,CAAC,MAAM;QACnB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE;YACP,aAAa,EAAE,eAAe,kBAAkB,GAAG;SACpD;KACF,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,gBAAgB,CAAC,MAA0B,EAAE;IACpD,OAAO;QACL,kBAAkB,EAAE,IAAI,CAAC;YACvB,WAAW,EACT,yKAAyK;YAC3K,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,MAAM;qBACd,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;qBAChC,QAAQ,EAAE;qBACV,QAAQ,CAAC,uDAAuD,CAAC;gBACpE,QAAQ,EAAE,IAAI,CAAC,MAAM;qBAClB,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;qBAC9C,QAAQ,EAAE;qBACV,QAAQ,CAAC,gCAAgC,CAAC;aAC9C;YACD,KAAK,CAAC,OAAO,CAAC,IAAI;gBAChB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACjB,OAAO,OAAO,kBAAkB,oEAAoE,CAAC;gBACvG,CAAC;gBACD,MAAM,UAAU,GAA4B,EAAE,CAAC;gBAC/C,IAAI,IAAI,CAAC,IAAI;oBAAE,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC3C,IAAI,IAAI,CAAC,QAAQ;oBAAE,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBACvD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,aAAa;oBACnB,SAAS,EAAE,UAAU;oBACrB,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;YACjD,CAAC;SACF,CAAC;QAEF,iBAAiB,EAAE,IAAI,CAAC;YACtB,WAAW,EACT,yHAAyH;YAC3H,IAAI,EAAE,EAAE;YACR,KAAK,CAAC,OAAO;gBACX,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACjB,OAAO,OAAO,kBAAkB,oEAAoE,CAAC;gBACvG,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;YACjD,CAAC;SACF,CAAC;QAEF,gBAAgB,EAAE,IAAI,CAAC;YACrB,WAAW,EACT,sGAAsG;YACxG,IAAI,EAAE;gBACJ,KAAK,EAAE,IAAI,CAAC,MAAM;qBACf,MAAM,EAAE;qBACR,KAAK,CAAC,yBAAyB,CAAC;qBAChC,QAAQ,EAAE;qBACV,QAAQ,CAAC,wCAAwC,CAAC;gBACrD,EAAE,EAAE,IAAI,CAAC,MAAM;qBACZ,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;qBACvB,QAAQ,EAAE;qBACV,QAAQ,CAAC,yDAAyD,CAAC;aACvE;YACD,KAAK,CAAC,OAAO,CAAC,IAAI;gBAChB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACjB,OAAO,OAAO,kBAAkB,oEAAoE,CAAC;gBACvG,CAAC;gBACD,MAAM,UAAU,GAA4B,EAAE,CAAC;gBAC/C,IAAI,IAAI,CAAC,KAAK;oBAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;gBAC9C,IAAI,IAAI,CAAC,EAAE;oBAAE,UAAU,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;gBACrC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,UAAU;oBACrB,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;YACjD,CAAC;SACF,CAAC;QAEF,YAAY,EAAE,IAAI,CAAC;YACjB,WAAW,EACT,4KAA4K;YAC9K,IAAI,EAAE;gBACJ,YAAY,EAAE,IAAI,CAAC,MAAM;qBACtB,OAAO,EAAE;qBACT,QAAQ,EAAE;qBACV,QAAQ,CACP,yGAAyG,CAC1G;aACJ;YACD,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO;gBACzB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;gBACpC,MAAM,KAAK,GAAa,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;gBACtC,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,MAAM;oBACT,CAAC,CAAC,GAAG,kBAAkB,yBAAyB;oBAChD,CAAC,CAAC,GAAG,kBAAkB,gDAAgD,CAC1E,CAAC;gBAEF,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAED,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC;oBACpC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;oBACd,KAAK,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;oBACnD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAEvB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;oBACvB,KAAK,CAAC,IAAI,CACR,0HAA0H,CAC3H,CAAC;oBACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAED,IAAI,CAAC;oBACH,MAAM,OAAO,CAAC,GAAG,CAAC;wBAChB,UAAU,EAAE,MAAM;wBAClB,QAAQ,EAAE,CAAC,eAAe,CAAC;wBAC3B,MAAM,EAAE,CAAC,eAAe,CAAC;wBACzB,QAAQ,EAAE;4BACR,MAAM,EACJ,qFAAqF;yBACxF;qBACF,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;oBACxD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAED,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;gBAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC9E,MAAM,KAAK,GACT,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC,IAAY,EAAE,QAAgB,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;gBAEjG,IAAI,MAAM,GAA4B;oBACpC,OAAO,EAAE,iCAAiC;iBAC3C,CAAC;gBACF,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnC,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACtC,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAAC,MAAM,CAAC;oBACP,kBAAkB;gBACpB,CAAC;gBAED,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjC,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,SAAS,EAAE,CAAC;oBACnC,KAAK,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;oBACrE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAED,MAAM,CAAC,GAAG,GAAG;oBACX,GAAG,GAAG;oBACN,CAAC,WAAW,CAAC,EAAE;wBACb,IAAI,EAAE,QAAQ;wBACd,GAAG,EAAE,IAAI,CAAC,MAAM;wBAChB,OAAO,EAAE,IAAI;wBACb,KAAK,EAAE,KAAK;wBACZ,OAAO,EAAE;4BACP,aAAa,EAAE,eAAe,kBAAkB,GAAG;yBACpD;qBACF;iBACF,CAAC;gBACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,MAAM,CAAC,OAAO,GAAG,iCAAiC,CAAC;gBACrD,CAAC;gBAED,IAAI,CAAC;oBACH,MAAM,KAAK,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;gBAClE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACvE,KAAK,CAAC,IAAI,CAAC,mCAAmC,UAAU,KAAK,OAAO,EAAE,CAAC,CAAC;oBACxE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,yBAAyB,UAAU,uBAAuB,kBAAkB,IAAI,CAAC,CAAC;gBAC7F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;SACF,CAAC;KACH,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,EAAE,CAAC;AAE9C,uEAAuE;AACvE,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bytesbrains/opencode-cruise",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "BytesBrains Cruise plugin for OpenCode — budgets, lanes, and OpenAI-compatible routing via the Cruise gateway.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"homepage": "https://bytesbrains.com/cruise",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/bytesbrains/cruise-opencode.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/bytesbrains/cruise-opencode/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"opencode",
|
|
17
|
+
"cruise",
|
|
18
|
+
"bytesbrains",
|
|
19
|
+
"llm",
|
|
20
|
+
"openai-compatible",
|
|
21
|
+
"byok",
|
|
22
|
+
"plugin"
|
|
23
|
+
],
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"rehearse:demo": "node scripts/rehearse-demo.mjs",
|
|
42
|
+
"pack:check": "node scripts/pack-check.mjs",
|
|
43
|
+
"prepack": "npm run build"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@opencode-ai/plugin": ">=1.4.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@opencode-ai/plugin": "^1.18.31",
|
|
53
|
+
"@types/node": "^24.5.2",
|
|
54
|
+
"typescript": "^5.9.2",
|
|
55
|
+
"vitest": "^5.0.1"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=22"
|
|
59
|
+
}
|
|
60
|
+
}
|