crewcode-plugin-cli 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 +202 -0
- package/README.md +39 -0
- package/bin/crewcode.mjs +388 -0
- package/package.json +40 -0
- package/templates/plugins/README.md +25 -0
- package/templates/plugins/browser-docs-grabber/crewcode-plugin-api.js +80 -0
- package/templates/plugins/browser-docs-grabber/crewcode.plugin.json +13 -0
- package/templates/plugins/browser-docs-grabber/panel.html +1 -0
- package/templates/plugins/browser-docs-grabber/plugin.js +1 -0
- package/templates/plugins/codebase-graph-lite/crewcode-plugin-api.js +80 -0
- package/templates/plugins/codebase-graph-lite/crewcode.plugin.json +57 -0
- package/templates/plugins/codebase-graph-lite/panel.html +53 -0
- package/templates/plugins/codebase-graph-lite/plugin.js +49 -0
- package/templates/plugins/company-agent-http-adapter/crewcode-plugin-api.js +80 -0
- package/templates/plugins/company-agent-http-adapter/crewcode.plugin.json +24 -0
- package/templates/plugins/company-agent-http-adapter/panel.html +1 -0
- package/templates/plugins/company-agent-http-adapter/plugin.js +1 -0
- package/templates/plugins/company-agent-http-adapter/server.mjs +27 -0
- package/templates/plugins/git-risk-lens/crewcode-plugin-api.js +80 -0
- package/templates/plugins/git-risk-lens/crewcode.plugin.json +13 -0
- package/templates/plugins/git-risk-lens/panel.html +1 -0
- package/templates/plugins/git-risk-lens/plugin.js +2 -0
- package/templates/plugins/github-copilot-cli-provider/crewcode-plugin-api.js +80 -0
- package/templates/plugins/github-copilot-cli-provider/crewcode.plugin.json +42 -0
- package/templates/plugins/github-copilot-cli-provider/panel.html +1 -0
- package/templates/plugins/github-copilot-cli-provider/plugin.js +1 -0
- package/templates/plugins/handoff-pack/crewcode-plugin-api.js +80 -0
- package/templates/plugins/handoff-pack/crewcode.plugin.json +72 -0
- package/templates/plugins/handoff-pack/panel.html +63 -0
- package/templates/plugins/handoff-pack/plugin.js +156 -0
- package/templates/plugins/mcp-server-template/README.md +22 -0
- package/templates/plugins/mcp-server-template/crewcode-plugin-api.js +80 -0
- package/templates/plugins/mcp-server-template/crewcode.plugin.json +30 -0
- package/templates/plugins/mcp-server-template/panel.html +25 -0
- package/templates/plugins/mcp-server-template/plugin.js +9 -0
- package/templates/plugins/mcp-server-template/server.mjs +30 -0
- package/templates/plugins/mission-ci-widget/crewcode-plugin-api.js +80 -0
- package/templates/plugins/mission-ci-widget/crewcode.plugin.json +13 -0
- package/templates/plugins/mission-ci-widget/panel.html +1 -0
- package/templates/plugins/mission-ci-widget/plugin.js +1 -0
- package/templates/plugins/mock-agent-provider/crewcode-plugin-api.js +80 -0
- package/templates/plugins/mock-agent-provider/crewcode.plugin.json +38 -0
- package/templates/plugins/mock-agent-provider/panel.html +45 -0
- package/templates/plugins/mock-agent-provider/plugin.js +3 -0
- package/templates/plugins/openai-compatible-provider/README.md +17 -0
- package/templates/plugins/openai-compatible-provider/crewcode-plugin-api.js +80 -0
- package/templates/plugins/openai-compatible-provider/crewcode.plugin.json +28 -0
- package/templates/plugins/openai-compatible-provider/panel.html +1 -0
- package/templates/plugins/openai-compatible-provider/plugin.js +4 -0
- package/templates/plugins/openai-compatible-provider/server.mjs +21 -0
- package/templates/plugins/repo-radar/crewcode-plugin-api.js +80 -0
- package/templates/plugins/repo-radar/crewcode.plugin.json +55 -0
- package/templates/plugins/repo-radar/panel.html +56 -0
- package/templates/plugins/repo-radar/plugin.js +103 -0
- package/templates/plugins/static-panel-template/README.md +19 -0
- package/templates/plugins/static-panel-template/crewcode-plugin-api.js +80 -0
- package/templates/plugins/static-panel-template/crewcode.plugin.json +44 -0
- package/templates/plugins/static-panel-template/panel.html +36 -0
- package/templates/plugins/static-panel-template/plugin.js +30 -0
- package/templates/plugins/terminal-watchdog-lite/crewcode-plugin-api.js +80 -0
- package/templates/plugins/terminal-watchdog-lite/crewcode.plugin.json +13 -0
- package/templates/plugins/terminal-watchdog-lite/panel.html +1 -0
- package/templates/plugins/terminal-watchdog-lite/plugin.js +1 -0
- package/templates/plugins/typescript-panel-template/README.md +40 -0
- package/templates/plugins/typescript-panel-template/compiled/assets/panel-ECHDDxZz.js +8 -0
- package/templates/plugins/typescript-panel-template/compiled/assets/panel-u6HzQzUF.css +1 -0
- package/templates/plugins/typescript-panel-template/compiled/src/panel.html +13 -0
- package/templates/plugins/typescript-panel-template/crewcode.plugin.json +23 -0
- package/templates/plugins/typescript-panel-template/package.json +19 -0
- package/templates/plugins/typescript-panel-template/src/crewcode-api.ts +146 -0
- package/templates/plugins/typescript-panel-template/src/main.tsx +38 -0
- package/templates/plugins/typescript-panel-template/src/panel.html +12 -0
- package/templates/plugins/typescript-panel-template/src/style.css +17 -0
- package/templates/plugins/typescript-panel-template/tsconfig.json +20 -0
- package/templates/plugins/typescript-panel-template/vite.config.ts +14 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Minimal stdio MCP skeleton for template authors.
|
|
4
|
+
// Replace this with a real MCP SDK server before using it in production.
|
|
5
|
+
process.stdin.setEncoding('utf8')
|
|
6
|
+
|
|
7
|
+
process.stdin.on('data', chunk => {
|
|
8
|
+
for (const line of chunk.split('\n')) {
|
|
9
|
+
const trimmed = line.trim()
|
|
10
|
+
if (!trimmed) continue
|
|
11
|
+
let message
|
|
12
|
+
try {
|
|
13
|
+
message = JSON.parse(trimmed)
|
|
14
|
+
} catch {
|
|
15
|
+
continue
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (message.method === 'initialize') {
|
|
19
|
+
process.stdout.write(JSON.stringify({
|
|
20
|
+
jsonrpc: '2.0',
|
|
21
|
+
id: message.id,
|
|
22
|
+
result: {
|
|
23
|
+
protocolVersion: '2024-11-05',
|
|
24
|
+
capabilities: { tools: {} },
|
|
25
|
+
serverInfo: { name: 'crewcode-local-context-template', version: '0.1.0' },
|
|
26
|
+
},
|
|
27
|
+
}) + '\n')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Official CrewCode plugin browser helper. GENERATED from src/ — do not edit by hand.
|
|
2
|
+
// Runs inside sandboxed plugin iframes. It never exposes Electron APIs.
|
|
3
|
+
"use strict";
|
|
4
|
+
(() => {
|
|
5
|
+
// src/create-api.ts
|
|
6
|
+
var CREWCODE_PLUGIN_API_VERSION = "0.1";
|
|
7
|
+
var RESERVED_NETWORK_MESSAGE = "crewcode.network.fetch is reserved in plugin API v0. Use an agentProvider runtime (http/sse-http/openai-compatible/websocket) for network access.";
|
|
8
|
+
var RESERVED_SECRETS_MESSAGE = "crewcode.secrets.get is reserved in plugin API v0. Use a provider apiKeyEnv or local CLI auth instead.";
|
|
9
|
+
function createCrewCodeApi(options = {}) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const timeoutMs = (_a = options.timeoutMs) != null ? _a : 1e4;
|
|
12
|
+
const targetOrigin = (_b = options.targetOrigin) != null ? _b : "*";
|
|
13
|
+
const pending = /* @__PURE__ */ new Map();
|
|
14
|
+
const contextListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
let seq = 0;
|
|
16
|
+
let latestContext = null;
|
|
17
|
+
const reportError = (err) => {
|
|
18
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
19
|
+
window.parent.postMessage({ type: "crewcode:runtimeError", message: error.message, stack: error.stack }, targetOrigin);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener("error", (event) => {
|
|
22
|
+
var _a2;
|
|
23
|
+
return reportError((_a2 = event.error) != null ? _a2 : event.message);
|
|
24
|
+
});
|
|
25
|
+
window.addEventListener("unhandledrejection", (event) => reportError(event.reason));
|
|
26
|
+
const request = (method, params) => {
|
|
27
|
+
const id = `req-${++seq}`;
|
|
28
|
+
window.parent.postMessage({ type: "crewcode:request", id, method, params }, targetOrigin);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
pending.set(id, { resolve, reject });
|
|
31
|
+
window.setTimeout(() => {
|
|
32
|
+
if (!pending.has(id)) return;
|
|
33
|
+
pending.delete(id);
|
|
34
|
+
reject(new Error("CrewCode plugin request timed out"));
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
window.addEventListener("message", (event) => {
|
|
39
|
+
if (event.source !== window.parent) return;
|
|
40
|
+
const msg = event.data;
|
|
41
|
+
if (!msg || typeof msg !== "object") return;
|
|
42
|
+
if (msg.type === "crewcode:context") {
|
|
43
|
+
latestContext = msg;
|
|
44
|
+
for (const listener of contextListeners) listener(latestContext);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (msg.type === "crewcode:response" && typeof msg.id === "string" && pending.has(msg.id)) {
|
|
48
|
+
const callbacks = pending.get(msg.id);
|
|
49
|
+
pending.delete(msg.id);
|
|
50
|
+
if (msg.ok) callbacks.resolve(msg.result);
|
|
51
|
+
else callbacks.reject(new Error(typeof msg.error === "string" ? msg.error : "plugin request failed"));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
apiVersion: CREWCODE_PLUGIN_API_VERSION,
|
|
56
|
+
request,
|
|
57
|
+
onContext(listener) {
|
|
58
|
+
contextListeners.add(listener);
|
|
59
|
+
if (latestContext) listener(latestContext);
|
|
60
|
+
return () => contextListeners.delete(listener);
|
|
61
|
+
},
|
|
62
|
+
getContext: () => latestContext,
|
|
63
|
+
workspace: {
|
|
64
|
+
listFiles: () => request("workspace:listFiles"),
|
|
65
|
+
readFile: (sub) => request("workspace:readFile", { sub }),
|
|
66
|
+
writeFile: (sub, text) => request("workspace:writeFile", { sub, text })
|
|
67
|
+
},
|
|
68
|
+
network: {
|
|
69
|
+
fetch: () => Promise.reject(new Error(RESERVED_NETWORK_MESSAGE))
|
|
70
|
+
},
|
|
71
|
+
secrets: {
|
|
72
|
+
get: () => Promise.reject(new Error(RESERVED_SECRETS_MESSAGE))
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/browser-global.ts
|
|
78
|
+
window.createCrewCodeApi = createCrewCodeApi;
|
|
79
|
+
window.crewcode = createCrewCodeApi();
|
|
80
|
+
})();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/crewcode.plugin.schema.json",
|
|
3
|
+
"id": "mission-ci-widget",
|
|
4
|
+
"name": "Mission CI Widget",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Dogfoods mission-control widget contributions with display-only CI status.",
|
|
7
|
+
"crewcode": { "apiVersion": "0.1" },
|
|
8
|
+
"permissions": [],
|
|
9
|
+
"contributes": {
|
|
10
|
+
"sidebarPanels": [{ "id": "ci", "title": "CI Widget", "icon": "activity", "entry": "panel.html" }],
|
|
11
|
+
"missionWidgets": [{ "id": "ci-status", "title": "CI Status", "text": "ci: local checks", "icon": "activity", "sidebarPanel": "ci" }]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><html><head><meta charset="utf-8"><title>Mission CI Widget</title><style>body{margin:0;background:#0f120f;color:#e5e7eb;font:13px Inter,system-ui;padding:16px}.mono{font-family:'JetBrains Mono',monospace;color:#8b9a91}.card{border:1px solid #1c2f2f;background:#121712;padding:12px;margin-top:12px}.ok{color:#86efac}</style></head><body><div class="mono">dogfood plugin</div><h1>mission ci widget</h1><p id="ctx">waiting for context…</p><div class="card"><div class="mono">local checks</div><h2 class="ok">ready</h2><p>Display-only mission widget. Future versions can route CI data through approved network/MCP capabilities.</p></div><script src="crewcode-plugin-api.js"></script><script src="plugin.js"></script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
window.crewcode.onContext(ctx=>{document.getElementById('ctx').textContent=ctx.workspace?`${ctx.workspace.name} · ${ctx.workspace.kind}`:'mission widget has no active workspace'})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Official CrewCode plugin browser helper. GENERATED from src/ — do not edit by hand.
|
|
2
|
+
// Runs inside sandboxed plugin iframes. It never exposes Electron APIs.
|
|
3
|
+
"use strict";
|
|
4
|
+
(() => {
|
|
5
|
+
// src/create-api.ts
|
|
6
|
+
var CREWCODE_PLUGIN_API_VERSION = "0.1";
|
|
7
|
+
var RESERVED_NETWORK_MESSAGE = "crewcode.network.fetch is reserved in plugin API v0. Use an agentProvider runtime (http/sse-http/openai-compatible/websocket) for network access.";
|
|
8
|
+
var RESERVED_SECRETS_MESSAGE = "crewcode.secrets.get is reserved in plugin API v0. Use a provider apiKeyEnv or local CLI auth instead.";
|
|
9
|
+
function createCrewCodeApi(options = {}) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const timeoutMs = (_a = options.timeoutMs) != null ? _a : 1e4;
|
|
12
|
+
const targetOrigin = (_b = options.targetOrigin) != null ? _b : "*";
|
|
13
|
+
const pending = /* @__PURE__ */ new Map();
|
|
14
|
+
const contextListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
let seq = 0;
|
|
16
|
+
let latestContext = null;
|
|
17
|
+
const reportError = (err) => {
|
|
18
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
19
|
+
window.parent.postMessage({ type: "crewcode:runtimeError", message: error.message, stack: error.stack }, targetOrigin);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener("error", (event) => {
|
|
22
|
+
var _a2;
|
|
23
|
+
return reportError((_a2 = event.error) != null ? _a2 : event.message);
|
|
24
|
+
});
|
|
25
|
+
window.addEventListener("unhandledrejection", (event) => reportError(event.reason));
|
|
26
|
+
const request = (method, params) => {
|
|
27
|
+
const id = `req-${++seq}`;
|
|
28
|
+
window.parent.postMessage({ type: "crewcode:request", id, method, params }, targetOrigin);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
pending.set(id, { resolve, reject });
|
|
31
|
+
window.setTimeout(() => {
|
|
32
|
+
if (!pending.has(id)) return;
|
|
33
|
+
pending.delete(id);
|
|
34
|
+
reject(new Error("CrewCode plugin request timed out"));
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
window.addEventListener("message", (event) => {
|
|
39
|
+
if (event.source !== window.parent) return;
|
|
40
|
+
const msg = event.data;
|
|
41
|
+
if (!msg || typeof msg !== "object") return;
|
|
42
|
+
if (msg.type === "crewcode:context") {
|
|
43
|
+
latestContext = msg;
|
|
44
|
+
for (const listener of contextListeners) listener(latestContext);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (msg.type === "crewcode:response" && typeof msg.id === "string" && pending.has(msg.id)) {
|
|
48
|
+
const callbacks = pending.get(msg.id);
|
|
49
|
+
pending.delete(msg.id);
|
|
50
|
+
if (msg.ok) callbacks.resolve(msg.result);
|
|
51
|
+
else callbacks.reject(new Error(typeof msg.error === "string" ? msg.error : "plugin request failed"));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
apiVersion: CREWCODE_PLUGIN_API_VERSION,
|
|
56
|
+
request,
|
|
57
|
+
onContext(listener) {
|
|
58
|
+
contextListeners.add(listener);
|
|
59
|
+
if (latestContext) listener(latestContext);
|
|
60
|
+
return () => contextListeners.delete(listener);
|
|
61
|
+
},
|
|
62
|
+
getContext: () => latestContext,
|
|
63
|
+
workspace: {
|
|
64
|
+
listFiles: () => request("workspace:listFiles"),
|
|
65
|
+
readFile: (sub) => request("workspace:readFile", { sub }),
|
|
66
|
+
writeFile: (sub, text) => request("workspace:writeFile", { sub, text })
|
|
67
|
+
},
|
|
68
|
+
network: {
|
|
69
|
+
fetch: () => Promise.reject(new Error(RESERVED_NETWORK_MESSAGE))
|
|
70
|
+
},
|
|
71
|
+
secrets: {
|
|
72
|
+
get: () => Promise.reject(new Error(RESERVED_SECRETS_MESSAGE))
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/browser-global.ts
|
|
78
|
+
window.createCrewCodeApi = createCrewCodeApi;
|
|
79
|
+
window.crewcode = createCrewCodeApi();
|
|
80
|
+
})();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/crewcode.plugin.schema.json",
|
|
3
|
+
"id": "mock-agent-provider",
|
|
4
|
+
"name": "Mock Agent Provider",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Dogfoods plugin-powered agent provider registration without shell, network, or secret access.",
|
|
7
|
+
"crewcode": { "apiVersion": "0.1" },
|
|
8
|
+
"permissions": ["agent:provider"],
|
|
9
|
+
"contributes": {
|
|
10
|
+
"tabs": [
|
|
11
|
+
{
|
|
12
|
+
"id": "main",
|
|
13
|
+
"title": "Mock Agent Provider",
|
|
14
|
+
"icon": "bot",
|
|
15
|
+
"entry": "panel.html",
|
|
16
|
+
"singleton": true
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"statusItems": [
|
|
20
|
+
{
|
|
21
|
+
"id": "mock-agent-status",
|
|
22
|
+
"title": "Mock Agent Provider",
|
|
23
|
+
"text": "mock agent",
|
|
24
|
+
"icon": "bot",
|
|
25
|
+
"tab": "main"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"agentProviders": [
|
|
29
|
+
{
|
|
30
|
+
"id": "mock-reviewer",
|
|
31
|
+
"title": "Mock Reviewer",
|
|
32
|
+
"runtime": "mock",
|
|
33
|
+
"description": "Echoes a deterministic bridge response to validate plugin agent lifecycle.",
|
|
34
|
+
"models": ["mock-default", "mock-fast"]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Mock Agent Provider</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { color-scheme: dark; --bg:#0f120f; --panel:#121712; --border:#1c2f2f; --text:#e5e7eb; --muted:#8b9a91; --accent:#285a48; --mono:'JetBrains Mono', ui-monospace, monospace; --sans:Inter, ui-sans-serif, system-ui, sans-serif; }
|
|
9
|
+
* { box-sizing:border-box; }
|
|
10
|
+
body { margin:0; background:var(--bg); color:var(--text); font:13px var(--sans); }
|
|
11
|
+
header { padding:16px; border-bottom:1px solid var(--border); }
|
|
12
|
+
h1 { margin:0; font-size:15px; letter-spacing:-0.02em; }
|
|
13
|
+
p { color:var(--muted); line-height:1.5; margin:6px 0 0; }
|
|
14
|
+
main { padding:14px; display:grid; gap:12px; }
|
|
15
|
+
.card { border:1px solid var(--border); background:var(--panel); padding:12px; }
|
|
16
|
+
.eyebrow, code, li { font-family:var(--mono); }
|
|
17
|
+
.eyebrow { color:var(--muted); font-size:10px; }
|
|
18
|
+
code { color:#dff3e9; font-size:11px; }
|
|
19
|
+
ul { margin:8px 0 0; padding-left:18px; color:#cdd7d1; }
|
|
20
|
+
li { margin:5px 0; font-size:12px; }
|
|
21
|
+
</style>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<header>
|
|
25
|
+
<div class="eyebrow">dogfood plugin</div>
|
|
26
|
+
<h1>mock agent provider</h1>
|
|
27
|
+
<p id="workspace">waiting for CrewCode context…</p>
|
|
28
|
+
</header>
|
|
29
|
+
<main>
|
|
30
|
+
<section class="card">
|
|
31
|
+
<p>This plugin contributes a bridge agent named <code>Mock Reviewer</code>.</p>
|
|
32
|
+
<ul>
|
|
33
|
+
<li>permission: <code>agent:provider</code></li>
|
|
34
|
+
<li>runtime: <code>mock</code></li>
|
|
35
|
+
<li>no shell, terminal, network, secrets, or filesystem access</li>
|
|
36
|
+
</ul>
|
|
37
|
+
</section>
|
|
38
|
+
<section class="card">
|
|
39
|
+
<p>After approval, open a chat or crew config and select <code>Mock Reviewer</code>. Sending a prompt should produce a deterministic mock response through the normal bridge lifecycle.</p>
|
|
40
|
+
</section>
|
|
41
|
+
</main>
|
|
42
|
+
<script src="crewcode-plugin-api.js"></script>
|
|
43
|
+
<script src="plugin.js"></script>
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# OpenAI compatible provider template
|
|
2
|
+
|
|
3
|
+
Use this when a local, hosted, or company gateway exposes the OpenAI `/v1/chat/completions` request/response shape.
|
|
4
|
+
|
|
5
|
+
## Try the local server
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
node server.mjs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then copy/approve the plugin and select `OpenAI Compatible Agent` in CrewCode.
|
|
12
|
+
|
|
13
|
+
## Manifest notes
|
|
14
|
+
|
|
15
|
+
- `runtime: "openai-compatible"`
|
|
16
|
+
- `endpoint` can be a base URL like `http://localhost:4000/v1`; CrewCode appends `/chat/completions`.
|
|
17
|
+
- `apiKeyEnv` is optional. If set and the environment variable exists, CrewCode sends `Authorization: Bearer ...`.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Official CrewCode plugin browser helper. GENERATED from src/ — do not edit by hand.
|
|
2
|
+
// Runs inside sandboxed plugin iframes. It never exposes Electron APIs.
|
|
3
|
+
"use strict";
|
|
4
|
+
(() => {
|
|
5
|
+
// src/create-api.ts
|
|
6
|
+
var CREWCODE_PLUGIN_API_VERSION = "0.1";
|
|
7
|
+
var RESERVED_NETWORK_MESSAGE = "crewcode.network.fetch is reserved in plugin API v0. Use an agentProvider runtime (http/sse-http/openai-compatible/websocket) for network access.";
|
|
8
|
+
var RESERVED_SECRETS_MESSAGE = "crewcode.secrets.get is reserved in plugin API v0. Use a provider apiKeyEnv or local CLI auth instead.";
|
|
9
|
+
function createCrewCodeApi(options = {}) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const timeoutMs = (_a = options.timeoutMs) != null ? _a : 1e4;
|
|
12
|
+
const targetOrigin = (_b = options.targetOrigin) != null ? _b : "*";
|
|
13
|
+
const pending = /* @__PURE__ */ new Map();
|
|
14
|
+
const contextListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
let seq = 0;
|
|
16
|
+
let latestContext = null;
|
|
17
|
+
const reportError = (err) => {
|
|
18
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
19
|
+
window.parent.postMessage({ type: "crewcode:runtimeError", message: error.message, stack: error.stack }, targetOrigin);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener("error", (event) => {
|
|
22
|
+
var _a2;
|
|
23
|
+
return reportError((_a2 = event.error) != null ? _a2 : event.message);
|
|
24
|
+
});
|
|
25
|
+
window.addEventListener("unhandledrejection", (event) => reportError(event.reason));
|
|
26
|
+
const request = (method, params) => {
|
|
27
|
+
const id = `req-${++seq}`;
|
|
28
|
+
window.parent.postMessage({ type: "crewcode:request", id, method, params }, targetOrigin);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
pending.set(id, { resolve, reject });
|
|
31
|
+
window.setTimeout(() => {
|
|
32
|
+
if (!pending.has(id)) return;
|
|
33
|
+
pending.delete(id);
|
|
34
|
+
reject(new Error("CrewCode plugin request timed out"));
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
window.addEventListener("message", (event) => {
|
|
39
|
+
if (event.source !== window.parent) return;
|
|
40
|
+
const msg = event.data;
|
|
41
|
+
if (!msg || typeof msg !== "object") return;
|
|
42
|
+
if (msg.type === "crewcode:context") {
|
|
43
|
+
latestContext = msg;
|
|
44
|
+
for (const listener of contextListeners) listener(latestContext);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (msg.type === "crewcode:response" && typeof msg.id === "string" && pending.has(msg.id)) {
|
|
48
|
+
const callbacks = pending.get(msg.id);
|
|
49
|
+
pending.delete(msg.id);
|
|
50
|
+
if (msg.ok) callbacks.resolve(msg.result);
|
|
51
|
+
else callbacks.reject(new Error(typeof msg.error === "string" ? msg.error : "plugin request failed"));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
apiVersion: CREWCODE_PLUGIN_API_VERSION,
|
|
56
|
+
request,
|
|
57
|
+
onContext(listener) {
|
|
58
|
+
contextListeners.add(listener);
|
|
59
|
+
if (latestContext) listener(latestContext);
|
|
60
|
+
return () => contextListeners.delete(listener);
|
|
61
|
+
},
|
|
62
|
+
getContext: () => latestContext,
|
|
63
|
+
workspace: {
|
|
64
|
+
listFiles: () => request("workspace:listFiles"),
|
|
65
|
+
readFile: (sub) => request("workspace:readFile", { sub }),
|
|
66
|
+
writeFile: (sub, text) => request("workspace:writeFile", { sub, text })
|
|
67
|
+
},
|
|
68
|
+
network: {
|
|
69
|
+
fetch: () => Promise.reject(new Error(RESERVED_NETWORK_MESSAGE))
|
|
70
|
+
},
|
|
71
|
+
secrets: {
|
|
72
|
+
get: () => Promise.reject(new Error(RESERVED_SECRETS_MESSAGE))
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/browser-global.ts
|
|
78
|
+
window.createCrewCodeApi = createCrewCodeApi;
|
|
79
|
+
window.crewcode = createCrewCodeApi();
|
|
80
|
+
})();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/crewcode.plugin.schema.json",
|
|
3
|
+
"id": "openai-compatible-provider",
|
|
4
|
+
"name": "OpenAI Compatible Provider",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Template for local/company model gateways that expose the OpenAI chat completions shape.",
|
|
7
|
+
"crewcode": { "apiVersion": "0.1" },
|
|
8
|
+
"permissions": ["agent:provider", "network:fetch"],
|
|
9
|
+
"contributes": {
|
|
10
|
+
"tabs": [
|
|
11
|
+
{ "id": "main", "title": "OpenAI Compatible", "icon": "bot", "entry": "panel.html", "singleton": true }
|
|
12
|
+
],
|
|
13
|
+
"agentProviders": [
|
|
14
|
+
{
|
|
15
|
+
"id": "local-openai-compatible",
|
|
16
|
+
"title": "OpenAI Compatible Agent",
|
|
17
|
+
"runtime": "openai-compatible",
|
|
18
|
+
"description": "POSTs to /v1/chat/completions and reads choices[0].message.content.",
|
|
19
|
+
"endpoint": "http://localhost:4000/v1",
|
|
20
|
+
"apiKeyEnv": "OPENAI_COMPATIBLE_API_KEY",
|
|
21
|
+
"timeoutMs": 90000,
|
|
22
|
+
"maxOutputBytes": 524288,
|
|
23
|
+
"responsePath": "choices.0.message.content",
|
|
24
|
+
"models": ["local-default"]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><html><head><meta charset="utf-8"><title>OpenAI Compatible Provider</title><style>body{margin:0;background:#0f120f;color:#e5e7eb;font:13px Inter,system-ui;padding:16px}.mono,code{font-family:'JetBrains Mono',monospace;color:#8b9a91}.card{border:1px solid #1c2f2f;background:#121712;padding:12px;margin-top:12px}pre{white-space:pre-wrap}</style></head><body><div class="mono">agent provider template</div><h1>openai compatible provider</h1><p id="ctx">waiting for context…</p><div class="card">CrewCode POSTs to <code>http://localhost:4000/v1/chat/completions</code> with <code>{ model, messages }</code>.</div><div class="card">If <code>OPENAI_COMPATIBLE_API_KEY</code> is set, CrewCode sends it as a bearer token. The manifest never stores secrets.</div><pre class="card">return JSON with choices[0].message.content</pre><script src="crewcode-plugin-api.js"></script><script src="plugin.js"></script></body></html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import http from 'node:http'
|
|
4
|
+
|
|
5
|
+
const server = http.createServer(async (req, res) => {
|
|
6
|
+
if (req.method !== 'POST' || req.url !== '/v1/chat/completions') {
|
|
7
|
+
res.writeHead(404)
|
|
8
|
+
res.end('not found')
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
let body = ''
|
|
12
|
+
for await (const chunk of req) body += chunk
|
|
13
|
+
const json = JSON.parse(body || '{}')
|
|
14
|
+
const prompt = json.messages?.at(-1)?.content ?? ''
|
|
15
|
+
res.setHeader('Content-Type', 'application/json')
|
|
16
|
+
res.end(JSON.stringify({
|
|
17
|
+
choices: [{ message: { content: `local openai-compatible template received ${String(prompt).length} characters.` } }],
|
|
18
|
+
}))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
server.listen(4000, () => console.log('openai-compatible template listening on http://localhost:4000/v1/chat/completions'))
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Official CrewCode plugin browser helper. GENERATED from src/ — do not edit by hand.
|
|
2
|
+
// Runs inside sandboxed plugin iframes. It never exposes Electron APIs.
|
|
3
|
+
"use strict";
|
|
4
|
+
(() => {
|
|
5
|
+
// src/create-api.ts
|
|
6
|
+
var CREWCODE_PLUGIN_API_VERSION = "0.1";
|
|
7
|
+
var RESERVED_NETWORK_MESSAGE = "crewcode.network.fetch is reserved in plugin API v0. Use an agentProvider runtime (http/sse-http/openai-compatible/websocket) for network access.";
|
|
8
|
+
var RESERVED_SECRETS_MESSAGE = "crewcode.secrets.get is reserved in plugin API v0. Use a provider apiKeyEnv or local CLI auth instead.";
|
|
9
|
+
function createCrewCodeApi(options = {}) {
|
|
10
|
+
var _a, _b;
|
|
11
|
+
const timeoutMs = (_a = options.timeoutMs) != null ? _a : 1e4;
|
|
12
|
+
const targetOrigin = (_b = options.targetOrigin) != null ? _b : "*";
|
|
13
|
+
const pending = /* @__PURE__ */ new Map();
|
|
14
|
+
const contextListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
let seq = 0;
|
|
16
|
+
let latestContext = null;
|
|
17
|
+
const reportError = (err) => {
|
|
18
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
19
|
+
window.parent.postMessage({ type: "crewcode:runtimeError", message: error.message, stack: error.stack }, targetOrigin);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener("error", (event) => {
|
|
22
|
+
var _a2;
|
|
23
|
+
return reportError((_a2 = event.error) != null ? _a2 : event.message);
|
|
24
|
+
});
|
|
25
|
+
window.addEventListener("unhandledrejection", (event) => reportError(event.reason));
|
|
26
|
+
const request = (method, params) => {
|
|
27
|
+
const id = `req-${++seq}`;
|
|
28
|
+
window.parent.postMessage({ type: "crewcode:request", id, method, params }, targetOrigin);
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
pending.set(id, { resolve, reject });
|
|
31
|
+
window.setTimeout(() => {
|
|
32
|
+
if (!pending.has(id)) return;
|
|
33
|
+
pending.delete(id);
|
|
34
|
+
reject(new Error("CrewCode plugin request timed out"));
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
window.addEventListener("message", (event) => {
|
|
39
|
+
if (event.source !== window.parent) return;
|
|
40
|
+
const msg = event.data;
|
|
41
|
+
if (!msg || typeof msg !== "object") return;
|
|
42
|
+
if (msg.type === "crewcode:context") {
|
|
43
|
+
latestContext = msg;
|
|
44
|
+
for (const listener of contextListeners) listener(latestContext);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (msg.type === "crewcode:response" && typeof msg.id === "string" && pending.has(msg.id)) {
|
|
48
|
+
const callbacks = pending.get(msg.id);
|
|
49
|
+
pending.delete(msg.id);
|
|
50
|
+
if (msg.ok) callbacks.resolve(msg.result);
|
|
51
|
+
else callbacks.reject(new Error(typeof msg.error === "string" ? msg.error : "plugin request failed"));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
apiVersion: CREWCODE_PLUGIN_API_VERSION,
|
|
56
|
+
request,
|
|
57
|
+
onContext(listener) {
|
|
58
|
+
contextListeners.add(listener);
|
|
59
|
+
if (latestContext) listener(latestContext);
|
|
60
|
+
return () => contextListeners.delete(listener);
|
|
61
|
+
},
|
|
62
|
+
getContext: () => latestContext,
|
|
63
|
+
workspace: {
|
|
64
|
+
listFiles: () => request("workspace:listFiles"),
|
|
65
|
+
readFile: (sub) => request("workspace:readFile", { sub }),
|
|
66
|
+
writeFile: (sub, text) => request("workspace:writeFile", { sub, text })
|
|
67
|
+
},
|
|
68
|
+
network: {
|
|
69
|
+
fetch: () => Promise.reject(new Error(RESERVED_NETWORK_MESSAGE))
|
|
70
|
+
},
|
|
71
|
+
secrets: {
|
|
72
|
+
get: () => Promise.reject(new Error(RESERVED_SECRETS_MESSAGE))
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/browser-global.ts
|
|
78
|
+
window.createCrewCodeApi = createCrewCodeApi;
|
|
79
|
+
window.crewcode = createCrewCodeApi();
|
|
80
|
+
})();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/crewcode.plugin.schema.json",
|
|
3
|
+
"id": "repo-radar",
|
|
4
|
+
"name": "Repo Radar",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Scans a workspace for TODOs, risky files, and large source files to help agents orient quickly.",
|
|
7
|
+
"crewcode": { "apiVersion": "0.1" },
|
|
8
|
+
"permissions": ["workspace:read"],
|
|
9
|
+
"contributes": {
|
|
10
|
+
"tabs": [
|
|
11
|
+
{
|
|
12
|
+
"id": "main",
|
|
13
|
+
"title": "Repo Radar",
|
|
14
|
+
"icon": "radar",
|
|
15
|
+
"entry": "panel.html",
|
|
16
|
+
"singleton": true
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"sidebarPanels": [
|
|
20
|
+
{
|
|
21
|
+
"id": "radar",
|
|
22
|
+
"title": "Radar",
|
|
23
|
+
"icon": "radar",
|
|
24
|
+
"entry": "panel.html"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"statusItems": [
|
|
28
|
+
{
|
|
29
|
+
"id": "radar-status",
|
|
30
|
+
"title": "Repo Radar",
|
|
31
|
+
"text": "radar",
|
|
32
|
+
"icon": "radar",
|
|
33
|
+
"sidebarPanel": "radar"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"editorActions": [
|
|
37
|
+
{
|
|
38
|
+
"id": "scan-current-context",
|
|
39
|
+
"title": "Scan workspace with Repo Radar",
|
|
40
|
+
"icon": "radar",
|
|
41
|
+
"sidebarPanel": "radar",
|
|
42
|
+
"filePattern": "*"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"chatActions": [
|
|
46
|
+
{
|
|
47
|
+
"id": "open-radar-from-chat",
|
|
48
|
+
"title": "Open Repo Radar",
|
|
49
|
+
"icon": "radar",
|
|
50
|
+
"sidebarPanel": "radar",
|
|
51
|
+
"messageRole": "any"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|