Files
awesome-copilot/plugins/the-workshop/com.github.copilot/extensions/signals-dashboard/local-delegation.mjs
T
github-actions[bot] 3e8da0a7c0 chore: publish from main
2026-08-17 05:43:12 +00:00

402 lines
14 KiB
JavaScript

import { createHash } from "node:crypto";
import { accessSync, constants as fsConstants, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
const PREFERENCES = new Set(["off", "on"]);
const SAFE_ROUTE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
/** @deprecated Repo-root state is rejected; kept only for docs/migration mentions. */
export const LOCAL_DELEGATION_STATE_FILE = ".local-delegation.json";
export const LOCAL_DELEGATION_ENV = "WORKSHOP_LOCAL_DELEGATION";
export const LOCAL_DELEGATION_SKILL_NAME = "local-agent-delegation";
export const LOCAL_DELEGATION_USER_STATE_DIR = join(".copilot", "workshop-local-delegation");
/**
* Stable user-local preference path for a workshop root.
* Permission state must NOT live in the cloned workshop (a repo can ship
* preference:on). Key by a hash of the canonical workshop path under ~/.copilot.
*/
export function localDelegationPreferencePath(workshopDir, {
home = homedir(),
resolvePath = (p) => p,
} = {}) {
if (typeof workshopDir !== "string" || !workshopDir) {
throw new Error("workshopDir is required");
}
let canonical = workshopDir;
try { canonical = resolvePath(workshopDir); } catch { /* keep input */ }
// Normalize separators only. Do not lowercase: on case-sensitive filesystems
// /work/Foo and /work/foo are distinct workshops and must not share state.
const key = createHash("sha256")
.update(String(canonical).replaceAll("\\", "/"))
.digest("hex")
.slice(0, 32);
return join(home, LOCAL_DELEGATION_USER_STATE_DIR, `${key}.json`);
}
export function isLocalDelegationPreference(value) {
return typeof value === "string" && PREFERENCES.has(value.toLowerCase());
}
export function normalizeLocalDelegationPreference(value, fallback = "off") {
return isLocalDelegationPreference(value) ? value.toLowerCase() : fallback;
}
// Windows Terminal / cmd reparse cannot safely carry long multi-space -i strings.
// Keep the orientation prompt short, ASCII, and quote-free. Local Delegation
// policy lives in WORKSHOP_LOCAL_DELEGATION=enabled + the installed skill — not
// on the CLI.
const MAX_ORIENT_PROMPT_CHARS = 280;
// Allow apostrophes (desk's). Ban double quotes, backticks, dashes that WT/cmd
// have split on, and classic cmd metacharacters.
const UNSAFE_ORIENT_CHARS = /["`—–|&<>^%!()\r\n]/;
export function isSafeDeskOrientPrompt(prompt) {
return typeof prompt === "string"
&& prompt.length > 0
&& prompt.length <= MAX_ORIENT_PROMPT_CHARS
&& !UNSAFE_ORIENT_CHARS.test(prompt);
}
/** One short ASCII notice operators can see in the session start prompt. */
export const LOCAL_DELEGATION_ORIENT_LINE = " Local Delegation env is enabled.";
export function deskOrientPrompt(deskName, { localDelegationEffective = false } = {}) {
// deskName is already constrained to a slug by the launcher; still keep the
// prompt free of punctuation that cmd/wt have historically mis-parsed.
let prompt = `You are sitting down at the ${deskName} desk in this workshop. ` +
`Read journal.md in this folder first to pick up where the last session ` +
`left off, then continue the desk's work. Write your journal before you stop.`;
// Only a single short ASCII line may ride on -i. Full policy stays in env + skill.
if (localDelegationEffective) {
const withNotice = prompt + LOCAL_DELEGATION_ORIENT_LINE;
if (isSafeDeskOrientPrompt(withNotice)) prompt = withNotice;
}
return prompt;
}
/**
* Operator-visible summary for open toasts and badges.
* Never claims savings; only reports effective state + route id when known.
*/
export function formatLocalDelegationOpenNotice(localDelegation) {
if (!localDelegation || typeof localDelegation !== "object") {
return { titleSuffix: "", detail: "" };
}
const routeId = localDelegation.availability?.routeId || null;
if (localDelegation.effective) {
const routePart = routeId ? ` · route ${routeId}` : "";
return {
titleSuffix: " · Local Delegation effective",
detail: `Local Delegation effective${routePart}`,
};
}
if (localDelegation.requested) {
return {
titleSuffix: " · local unavailable",
detail: localDelegation.warning
|| localDelegation.availability?.reason
|| "Local Delegation requested but unavailable",
};
}
return { titleSuffix: "", detail: "" };
}
export function buildLocalDelegationLaunchEnv(baseEnv = {}, { localDelegationEffective = false } = {}) {
const env = { ...baseEnv };
// Windows env names are case-insensitive; spreading process.env yields a
// case-sensitive object, so clear every spelling before optionally setting.
const target = LOCAL_DELEGATION_ENV.toLowerCase();
for (const key of Object.keys(env)) {
if (key.toLowerCase() === target) delete env[key];
}
if (localDelegationEffective) {
env[LOCAL_DELEGATION_ENV] = "enabled";
}
return env;
}
/**
* cmd.exe prefix that forces WORKSHOP_LOCAL_DELEGATION on or off inside a new
* Windows Terminal / console session. wt.exe does not reliably forward the
* caller's process env into a new tab when Terminal is already running.
*/
export function windowsLocalDelegationCmdPrefix(localDelegationEffective = false) {
return localDelegationEffective
? 'set "WORKSHOP_LOCAL_DELEGATION=enabled"&& '
: 'set "WORKSHOP_LOCAL_DELEGATION="&& ';
}
/**
* Savings credit is utilization accounting, not a price claim.
* Failed, unaccepted, redone, or escalated local work earns zero.
*/
export function localSavingsCredit({
attempted = false,
gateAccepted = false,
redone = false,
escalated = false,
} = {}) {
if (!attempted || !gateAccepted || redone || escalated) {
return {
credit: 0,
utilization: attempted ? "handled_locally_unaccepted" : "not_attempted",
reason: !attempted
? "not_attempted"
: escalated
? "escalated"
: redone
? "redone"
: "gate_not_accepted",
};
}
return {
credit: 0, // dollar savings are never claimed by Cairn
utilization: "handled_locally_accepted",
reason: "accepted_utilization_only",
};
}
function isReadableFile(path) {
try {
if (!statSync(path).isFile()) return false;
accessSync(path, fsConstants.R_OK);
return true;
} catch {
return false;
}
}
function skillMarkerPath(dir) {
return join(dir, "SKILL.md");
}
function looksLikeSkillDir(dir) {
return isReadableFile(skillMarkerPath(dir));
}
/**
* Discover the installed local-agent-delegation skill.
* Injectable probes keep unit tests filesystem-free.
*/
export function findLocalDelegationSkillDir({
env = process.env,
home = homedir(),
exists = existsSync,
isSkillDir = looksLikeSkillDir,
} = {}) {
const explicit = (env.WORKSHOP_LOCAL_DELEGATION_SKILL_DIR || "").trim();
if (explicit) {
return isSkillDir(explicit) ? explicit : null;
}
const candidates = [
join(home, ".copilot", "skills", LOCAL_DELEGATION_SKILL_NAME),
join(home, ".agents", "skills", LOCAL_DELEGATION_SKILL_NAME),
];
for (const candidate of candidates) {
if (isSkillDir(candidate)) return candidate;
}
// Marketplace: ~/.copilot/installed-plugins/<marketplace>/<plugin>/
// Direct: ~/.copilot/installed-plugins/_direct/<plugin>/
// Skill dirs may live at skills/, .github/skills/, or com.github.copilot/skills/.
const pluginsRoot = join(home, ".copilot", "installed-plugins");
if (exists(pluginsRoot)) {
try {
for (const market of readdirSync(pluginsRoot, { withFileTypes: true })) {
if (!market.isDirectory()) continue;
const marketRoot = join(pluginsRoot, market.name);
let pluginEntries;
try {
pluginEntries = readdirSync(marketRoot, { withFileTypes: true });
} catch {
continue;
}
for (const plugin of pluginEntries) {
if (!plugin.isDirectory()) continue;
const pluginRoot = join(marketRoot, plugin.name);
const nestedCandidates = [
join(pluginRoot, "skills", LOCAL_DELEGATION_SKILL_NAME),
join(pluginRoot, ".github", "skills", LOCAL_DELEGATION_SKILL_NAME),
join(pluginRoot, "com.github.copilot", "skills", LOCAL_DELEGATION_SKILL_NAME),
join(pluginRoot, "com.github.awesome-copilot", "skills", LOCAL_DELEGATION_SKILL_NAME),
];
for (const nested of nestedCandidates) {
if (isSkillDir(nested)) return nested;
}
}
}
} catch {
// fail closed on scan errors
}
}
return null;
}
function readJsonFile(path, readFile = readFileSync) {
try {
return JSON.parse(readFile(path, "utf8"));
} catch {
return null;
}
}
function isRouteId(value) {
return typeof value === "string" && SAFE_ROUTE_ID.test(value);
}
/**
* Fail-closed availability. Enable only when skill + qualified route receipt
* (or explicit env route id) are present. Never invent availability.
*/
export function resolveLocalDelegationAvailability({
env = process.env,
home = homedir(),
now = Date.now(),
findSkill = findLocalDelegationSkillDir,
readFile = readFileSync,
exists = existsSync,
} = {}) {
const forced = (env.WORKSHOP_LOCAL_DELEGATION_AVAILABLE || "").trim().toLowerCase();
if (forced === "0" || forced === "false" || forced === "unavailable") {
return {
available: false,
reason: "Forced unavailable by WORKSHOP_LOCAL_DELEGATION_AVAILABLE",
skillDir: null,
routeId: null,
};
}
const skillDir = findSkill({ env, home, exists });
if (!skillDir) {
return {
available: false,
reason: "local-agent-delegation skill is not installed",
skillDir: null,
routeId: null,
};
}
const envRoute = (env.WORKSHOP_LOCAL_DELEGATION_ROUTE_ID || "").trim();
if (envRoute) {
if (!isRouteId(envRoute)) {
return {
available: false,
reason: "WORKSHOP_LOCAL_DELEGATION_ROUTE_ID is not a safe route id",
skillDir,
routeId: null,
};
}
return {
available: true,
reason: "Skill installed; route id provided by environment",
skillDir,
routeId: envRoute,
};
}
const receiptPath = (env.WORKSHOP_LOCAL_DELEGATION_RECEIPT || "").trim()
|| join(home, ".copilot", "local-agent-runs", "qualified-route.json");
if (!exists(receiptPath)) {
return {
available: false,
reason: "No qualified route receipt (set WORKSHOP_LOCAL_DELEGATION_ROUTE_ID or write ~/.copilot/local-agent-runs/qualified-route.json)",
skillDir,
routeId: null,
};
}
const receipt = readJsonFile(receiptPath, readFile);
if (!receipt || typeof receipt !== "object") {
return {
available: false,
reason: "Qualified route receipt is unreadable",
skillDir,
routeId: null,
};
}
const status = String(receipt.status || "").toLowerCase();
if (status !== "qualified") {
return {
available: false,
reason: `Route receipt status is '${receipt.status || "missing"}', not qualified`,
skillDir,
routeId: isRouteId(receipt.route_id || receipt.routeId) ? (receipt.route_id || receipt.routeId) : null,
};
}
const routeId = receipt.route_id || receipt.routeId || null;
if (!isRouteId(routeId)) {
return {
available: false,
reason: "Route receipt is missing a safe route_id",
skillDir,
routeId: null,
};
}
if (receipt.expires_at || receipt.expiresAt) {
const expires = Date.parse(receipt.expires_at || receipt.expiresAt);
if (!Number.isFinite(expires) || expires <= now) {
return {
available: false,
reason: "Qualified route receipt has expired",
skillDir,
routeId,
};
}
}
return {
available: true,
reason: "Skill installed; qualified route receipt present",
skillDir,
routeId,
};
}
export function resolveLocalDelegationLaunch({
preference = "off",
availability,
} = {}) {
const pref = normalizeLocalDelegationPreference(preference, "off");
const available = Boolean(availability?.available);
if (pref === "on" && !available) {
return {
preference: pref,
requested: true,
effective: false,
availability,
warning: availability?.reason || "Local Delegation unavailable",
};
}
return {
preference: pref,
requested: pref === "on",
effective: pref === "on" && available,
availability,
warning: null,
};
}
export function parseLocalDelegationState(raw) {
if (!raw || typeof raw !== "object") {
return { preference: "off" };
}
return {
preference: normalizeLocalDelegationPreference(raw.preference, "off"),
};
}
export function serializeLocalDelegationState(state) {
return {
preference: normalizeLocalDelegationPreference(state?.preference, "off"),
updatedAt: new Date().toISOString(),
};
}