mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-08 10:09:37 +00:00
chore: publish from main
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# Signals Dashboard Plugin
|
||||
|
||||
Real-time Workshop dashboard with agent signals, honesty calibration, and cost-aware repo or connected desk launch profiles.
|
||||
|
||||
## Installation
|
||||
|
||||
``bash
|
||||
copilot plugin install signals-dashboard@awesome-copilot
|
||||
``
|
||||
|
||||
## Source
|
||||
|
||||
This plugin is part of [Awesome Copilot](https://github.com/github/awesome-copilot).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
const PROFILES = new Set(["repo", "connected"]);
|
||||
const SAFE_MCP_NAME = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
||||
|
||||
export function isDeskProfile(value) {
|
||||
return typeof value === "string" && PROFILES.has(value.toLowerCase());
|
||||
}
|
||||
|
||||
export function normalizeDeskProfile(value, fallback = "repo") {
|
||||
return isDeskProfile(value) ? value.toLowerCase() : fallback;
|
||||
}
|
||||
|
||||
export function isWindowsAppExecutionAlias(candidate, localAppData) {
|
||||
if (typeof candidate !== "string" || typeof localAppData !== "string") return false;
|
||||
const normalized = candidate.replaceAll("/", "\\").toLowerCase();
|
||||
const root = `${localAppData.replaceAll("/", "\\").replace(/\\+$/, "")}` +
|
||||
"\\microsoft\\windowsapps\\";
|
||||
return normalized.startsWith(root.toLowerCase()) && normalized.endsWith(".exe");
|
||||
}
|
||||
|
||||
export function quoteWindowsCmdArgument(value) {
|
||||
return `"${String(value).replaceAll('"', '""')}"`;
|
||||
}
|
||||
|
||||
export function isSafeWindowsCmdShim(value) {
|
||||
return typeof value === "string" && !/[%\r\n]/.test(value);
|
||||
}
|
||||
|
||||
export function parsePluginMcpNames(text) {
|
||||
let parsed;
|
||||
try { parsed = JSON.parse(text); }
|
||||
catch {
|
||||
// Agency may prefix its pass-through command with human-readable startup
|
||||
// lines. Its underlying Copilot JSON is the final object in stdout.
|
||||
let start = text.lastIndexOf("{");
|
||||
while (start >= 0) {
|
||||
try {
|
||||
parsed = JSON.parse(text.slice(start));
|
||||
break;
|
||||
} catch {
|
||||
start = text.lastIndexOf("{", start - 1);
|
||||
}
|
||||
}
|
||||
if (start < 0) return null;
|
||||
}
|
||||
|
||||
if (!Array.isArray(parsed?.plugins)) return null;
|
||||
|
||||
const names = [];
|
||||
const seen = new Set();
|
||||
for (const entry of parsed.plugins) {
|
||||
if (entry?.kind !== "mcp" || entry.enabled === false) continue;
|
||||
if (entry.scope !== "plugin" && entry.source !== "plugin") continue;
|
||||
if (typeof entry.name !== "string" || !SAFE_MCP_NAME.test(entry.name)) continue;
|
||||
if (!seen.has(entry.name)) {
|
||||
seen.add(entry.name);
|
||||
names.push(entry.name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
export function buildDeskAgentArgv({
|
||||
deskName,
|
||||
workshopDir,
|
||||
useAgency,
|
||||
agencyCommand = "agency",
|
||||
copilotCommand = "copilot",
|
||||
profile = "repo",
|
||||
pluginMcpNames = [],
|
||||
discoverySucceeded = true,
|
||||
}) {
|
||||
const argv = useAgency
|
||||
? [agencyCommand, "copilot"]
|
||||
: [copilotCommand, "--name", deskName];
|
||||
|
||||
if (profile === "repo") {
|
||||
if (useAgency) argv.push("--no-default-mcps");
|
||||
}
|
||||
|
||||
if (profile === "repo" && discoverySucceeded) {
|
||||
for (const name of pluginMcpNames) {
|
||||
if (SAFE_MCP_NAME.test(name)) argv.push("--disable-mcp-server", name);
|
||||
}
|
||||
}
|
||||
|
||||
argv.push("--add-dir", workshopDir);
|
||||
return argv;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
buildDeskAgentArgv,
|
||||
isDeskProfile,
|
||||
isSafeWindowsCmdShim,
|
||||
isWindowsAppExecutionAlias,
|
||||
normalizeDeskProfile,
|
||||
parsePluginMcpNames,
|
||||
quoteWindowsCmdArgument,
|
||||
} from "./launch-profile.mjs";
|
||||
|
||||
test("normalizes supported profiles and defaults unknown values to repo", () => {
|
||||
assert.equal(isDeskProfile("repo"), true);
|
||||
assert.equal(isDeskProfile("CONNECTED"), true);
|
||||
assert.equal(isDeskProfile("other"), false);
|
||||
assert.equal(normalizeDeskProfile("CONNECTED"), "connected");
|
||||
assert.equal(normalizeDeskProfile("other"), "repo");
|
||||
});
|
||||
|
||||
test("recognizes Windows App Execution Alias paths without trusting repository executables", () => {
|
||||
assert.equal(isWindowsAppExecutionAlias(
|
||||
"C:\\Users\\person\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe",
|
||||
"C:\\Users\\person\\AppData\\Local"), true);
|
||||
assert.equal(isWindowsAppExecutionAlias(
|
||||
"C:\\repo\\wt.exe",
|
||||
"C:\\Users\\person\\AppData\\Local"), false);
|
||||
assert.equal(isWindowsAppExecutionAlias(
|
||||
"C:\\Users\\person\\AppData\\Local\\Microsoft\\WindowsApps\\wt.cmd",
|
||||
"C:\\Users\\person\\AppData\\Local"), false);
|
||||
});
|
||||
|
||||
test("quotes trusted cmd shim arguments and rejects percent-bearing paths", () => {
|
||||
assert.equal(
|
||||
quoteWindowsCmdArgument("C:\\Program Files\\Agency\\agency.cmd"),
|
||||
"\"C:\\Program Files\\Agency\\agency.cmd\"");
|
||||
assert.equal(quoteWindowsCmdArgument("--scope"), "\"--scope\"");
|
||||
assert.equal(isSafeWindowsCmdShim("C:\\Program Files\\Agency\\agency.cmd"), true);
|
||||
assert.equal(isSafeWindowsCmdShim("C:\\Users\\%USERNAME%\\agency.cmd"), false);
|
||||
});
|
||||
|
||||
test("executes a Windows cmd shim with safe quoting", {
|
||||
skip: process.platform !== "win32",
|
||||
}, () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "workshop-profile-"));
|
||||
const shimDir = join(root, "Shim Name");
|
||||
mkdirSync(shimDir);
|
||||
const shim = join(shimDir, "copilot.cmd");
|
||||
writeFileSync(shim, "@echo off\r\necho {\"plugins\":[]}\r\n");
|
||||
|
||||
const cmd = join(process.env.SystemRoot, "System32", "cmd.exe");
|
||||
const commandLine = `"${[shim, "plugins", "list"]
|
||||
.map(quoteWindowsCmdArgument)
|
||||
.join(" ")}"`;
|
||||
const result = spawnSync(cmd, ["/d", "/s", "/c", commandLine], {
|
||||
encoding: "utf8",
|
||||
windowsHide: true,
|
||||
windowsVerbatimArguments: true,
|
||||
});
|
||||
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.match(result.stdout, /\{"plugins":\[\]\}/);
|
||||
});
|
||||
|
||||
test("extracts enabled plugin-scoped MCP names and rejects unsafe names", () => {
|
||||
const names = parsePluginMcpNames(JSON.stringify({
|
||||
plugins: [
|
||||
{ kind: "mcp", name: "teams", scope: "plugin", enabled: true },
|
||||
{ kind: "mcp", name: "repo-mcp", source: "plugin", enabled: true },
|
||||
{ kind: "mcp", name: "teams", scope: "plugin", enabled: true },
|
||||
{ kind: "mcp", name: "disabled", scope: "plugin", enabled: false },
|
||||
{ kind: "mcp", name: "workspace", scope: "repository", enabled: true },
|
||||
{ kind: "skill", name: "not-an-mcp", scope: "plugin", enabled: true },
|
||||
{ kind: "mcp", name: "bad;name", scope: "plugin", enabled: true },
|
||||
],
|
||||
}));
|
||||
|
||||
assert.deepEqual(names, ["teams", "repo-mcp"]);
|
||||
assert.deepEqual(parsePluginMcpNames(`Agency startup\n${JSON.stringify({
|
||||
plugins: [{ kind: "mcp", name: "ado", scope: "plugin", enabled: true }],
|
||||
})}`), ["ado"]);
|
||||
assert.equal(parsePluginMcpNames("not json"), null);
|
||||
assert.equal(parsePluginMcpNames("{}"), null);
|
||||
});
|
||||
|
||||
test("builds an Agency repo profile on top of the existing wrapper", () => {
|
||||
assert.deepEqual(buildDeskAgentArgv({
|
||||
deskName: "cost-desk",
|
||||
workshopDir: "C:\\workshop",
|
||||
useAgency: true,
|
||||
agencyCommand: "C:\\tools\\agency.exe",
|
||||
profile: "repo",
|
||||
pluginMcpNames: ["teams", "ado"],
|
||||
}), [
|
||||
"C:\\tools\\agency.exe", "copilot", "--no-default-mcps",
|
||||
"--disable-mcp-server", "teams",
|
||||
"--disable-mcp-server", "ado",
|
||||
"--add-dir", "C:\\workshop",
|
||||
]);
|
||||
});
|
||||
|
||||
test("builds a plain Copilot repo profile without Agency-only flags", () => {
|
||||
assert.deepEqual(buildDeskAgentArgv({
|
||||
deskName: "cost-desk",
|
||||
workshopDir: "/workshop",
|
||||
useAgency: false,
|
||||
copilotCommand: "/usr/local/bin/copilot",
|
||||
profile: "repo",
|
||||
pluginMcpNames: ["calendar"],
|
||||
}), [
|
||||
"/usr/local/bin/copilot", "--name", "cost-desk",
|
||||
"--disable-mcp-server", "calendar",
|
||||
"--add-dir", "/workshop",
|
||||
]);
|
||||
});
|
||||
|
||||
test("connected preserves tools while Agency discovery failure still removes defaults", () => {
|
||||
assert.deepEqual(buildDeskAgentArgv({
|
||||
deskName: "cost-desk",
|
||||
workshopDir: "/workshop",
|
||||
useAgency: true,
|
||||
profile: "connected",
|
||||
pluginMcpNames: ["teams"],
|
||||
}), [
|
||||
"agency", "copilot", "--add-dir", "/workshop",
|
||||
]);
|
||||
|
||||
assert.deepEqual(buildDeskAgentArgv({
|
||||
deskName: "cost-desk",
|
||||
workshopDir: "/workshop",
|
||||
useAgency: true,
|
||||
profile: "repo",
|
||||
pluginMcpNames: [],
|
||||
discoverySucceeded: false,
|
||||
}), [
|
||||
"agency", "copilot", "--no-default-mcps", "--add-dir", "/workshop",
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "signals-dashboard",
|
||||
"version": "0.2.0",
|
||||
"type": "module",
|
||||
"main": "extension.mjs",
|
||||
"scripts": {
|
||||
"test": "node --test launch-profile.test.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@github/copilot-sdk": "latest"
|
||||
},
|
||||
"description": "Real-time Workshop dashboard with agent signals, honesty calibration, and cost-aware repo or connected desk launch profiles.",
|
||||
"keywords": [
|
||||
"agent-signals",
|
||||
"dashboard",
|
||||
"multi-agent",
|
||||
"coordination",
|
||||
"canvas"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
||||
"name": "signals-dashboard",
|
||||
"description": "Real-time Workshop dashboard with agent signals, honesty calibration, and cost-aware repo or connected desk launch profiles.",
|
||||
"version": "0.2.0",
|
||||
"author": {
|
||||
"name": "jennyf19",
|
||||
"url": "https://github.com/jennyf19"
|
||||
},
|
||||
"keywords": [
|
||||
"agent-signals",
|
||||
"dashboard",
|
||||
"multi-agent",
|
||||
"coordination",
|
||||
"canvas"
|
||||
],
|
||||
"extensions": {
|
||||
"com.github.copilot": {
|
||||
"logo": "assets/preview.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user