Skip to content

feat: add fail-closed Local Delegation to Cairn (signals-dashboard 0.3.0) - #2666

Open
jennyf19 wants to merge 10 commits into
github:mainfrom
jennyf19:feat/local-delegation-launch
Open

feat: add fail-closed Local Delegation to Cairn (signals-dashboard 0.3.0)#2666
jennyf19 wants to merge 10 commits into
github:mainfrom
jennyf19:feat/local-delegation-launch

Conversation

@jennyf19

Copy link
Copy Markdown
Contributor

Summary

Ports the Local Delegation seam from jennyf19/the-workshop#18 into the awesome-copilot signals-dashboard canvas (v0.3.0) and Workshop plugin docs.

  • Orthogonal Local off/on control beside existing repo / connected desk profiles
  • Fail-closed availability: installed local-agent-delegation skill and qualified route receipt / WORKSHOP_LOCAL_DELEGATION_ROUTE_ID
  • When effective: launch sets WORKSHOP_LOCAL_DELEGATION=enabled and appends a frontier-owned orientation note
  • Unavailable "on" requests still launch as frontier desks and surface the reason — no silent savings credit
  • Regenerated marketplace.json (signals-dashboard → 0.3.0)

Runtime/launcher/gates remain in sealed-delegation. Cairn owns only toggle, availability, launch instruction, and visible state.

Test plan

  • node --test extensions/signals-dashboard/launch-profile.test.mjs extensions/signals-dashboard/local-delegation.test.mjs (17/17)
  • node eng/generate-marketplace.mjs
  • CI: canvas validation, line endings, marketplace/materialized files
  • Maintainer review

Port the-workshop Local Delegation seam into signals-dashboard 0.3.0.
Orthogonal off/on control beside repo/connected profiles; enable only when
local-agent-delegation is installed and a qualified route receipt is present.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
@jennyf19
jennyf19 requested a review from aaronpowell as a code owner August 14, 2026 17:30
Copilot AI balanced review requested due to automatic review settings August 14, 2026 17:30
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

🔒 PR Risk Scan Results

Scanned 11 changed file(s).

Severity Count
🔴 High 0
🟠 Medium 1
ℹ️ Info 0
Severity Rule File Line Match
🟠 unpinned-version-indicator extensions/signals-dashboard/package.json 10 "@​​github/copilot-sdk": "latest"

This is an automated soft-gate report. Findings indicate review targets and do not block merge by themselves.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports fail-closed Local Delegation into Cairn while keeping repo/connected profiles independent.

Changes:

  • Adds delegation availability, state, launch environment, UI, and API handling.
  • Adds unit tests and extension documentation.
  • Bumps Signals Dashboard to v0.3.0 and updates marketplace metadata.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
plugins/the-workshop/README.md Documents the Local toggle.
plugins/signals-dashboard/plugin.json Updates metadata and version.
extensions/signals-dashboard/README.md Documents Cairn and delegation behavior.
extensions/signals-dashboard/package.json Bumps version and adds tests.
extensions/signals-dashboard/local-delegation.test.mjs Tests delegation behavior.
extensions/signals-dashboard/local-delegation.mjs Implements availability and launch state.
extensions/signals-dashboard/extension.mjs Integrates delegation into Cairn.
.github/plugin/marketplace.json Publishes v0.3.0 metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread plugins/signals-dashboard/plugin.json
Comment thread extensions/signals-dashboard/local-delegation.mjs Outdated
- Walk marketplace/plugin and _direct install roots for local-agent-delegation
- Update plugins/signals-dashboard README and regenerate docs/README.plugins.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Suppressed comments (1)

extensions/signals-dashboard/extension.mjs:801

  • This is an on/off toggle, but its accessible name only describes the next action and does not expose the current pressed state. Add aria-pressed based on the stored preference so screen-reader users can determine whether Local Delegation is selected, including the requested-but-unavailable state.
        <button data-act="local-delegation" data-preference="${esc(next)}"
            aria-label="Set Local Delegation ${esc(next)}"

Comment thread extensions/signals-dashboard/local-delegation.test.mjs Outdated
Comment thread extensions/signals-dashboard/extension.mjs Outdated
Long LD orientation text split under wt/cmd on Windows (0x80070002). Keep
-i short/quote-free; rely on WORKSHOP_LOCAL_DELEGATION=enabled (+ skill)
for policy. Add charset/length guard tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 18:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (3)

extensions/signals-dashboard/local-delegation.mjs:54

  • Windows environment variable names are case-insensitive, but spreading process.env creates a normal case-sensitive object. Deleting only the canonical spelling leaves a parent key such as workshop_local_delegation=enabled, so an off launch can still inherit delegation as enabled. Remove all case-insensitive matches before optionally adding the canonical key.
        delete env[LOCAL_DELEGATION_ENV];

extensions/signals-dashboard/extension.mjs:416

  • On Windows, wt.exe does not pass the caller's process environment to the command created in a new tab (especially when Terminal is already running). Both wt branches therefore report Local Delegation as effective while the launched Copilot process may never receive WORKSHOP_LOCAL_DELEGATION=enabled; an off launch can likewise inherit a stale value from the Terminal broker. The terminal command needs to set or clear the variable explicitly before starting the agent, with coverage for both states.
        if (direct && wt && await trySpawn(wt, ["-d", deskPath, ...run], { env })) return true;

extensions/signals-dashboard/local-delegation.mjs:44

  • This intentionally makes the effective-on and off prompts identical, contradicting the PR summary's promised frontier-owned orientation note and the linked Sealed Delegation launch contract, which says the desk instruction should establish the authority boundary. The installed skill does not consume this environment flag itself, so the toggle currently changes no frontier instruction. Add a short shell-safe instruction (or another enforced handoff) when effective, or revise the stated contract if env-only behavior is intended.

This issue also appears on line 54 of the same file.

    // localDelegationEffective is intentionally unused in the -i string: policy
    // is carried by env + skill so Windows launch cannot reparse a long appendix.
    void localDelegationEffective;

Keep -i short with one optional ASCII line. Show operators
"Local Delegation effective · route <id>" on open and in the summary control.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 19:15
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

🔴 Contributor Reputation Check: HIGH risk

Check Risk
Profile HIGH
Credential audit MEDIUM

Maintainers: please review this contributor before merging.
See the workflow run for full details.
Automated check powered by AGT.

@github-actions github-actions Bot added the needs-review:HIGH Contributor reputation check flagged HIGH risk label Aug 14, 2026
@github-actions github-actions Bot added canvas-extension PR touches canvas extensions plugin PR touches plugins labels Aug 14, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (3)

extensions/signals-dashboard/extension.mjs:417

  • When wt.exe attaches to an already-running Windows Terminal instance, the new tab inherits the Terminal server's environment rather than the environment passed to this wt.exe client. Consequently an effective launch can omit WORKSHOP_LOCAL_DELEGATION, while an off launch can retain a stale enabled value, despite Cairn reporting the requested state. Set or clear the variable inside the command executed in the new tab (for both direct and cmd-shim branches), rather than relying on spawn(..., { env }).
        if (direct && wt && await trySpawn(wt, ["-d", deskPath, ...run], { env })) return true;

extensions/signals-dashboard/extension.mjs:387

  • This recomputes availability synchronously on every render/open. The dashboard refreshes / every five seconds, and the common unavailable case makes findLocalDelegationSkillDir synchronously traverse every installed marketplace/plugin and probe up to four paths per plugin each time, blocking the server event loop and creating continuous filesystem churn. Cache this probe for a bounded TTL (as MCP discovery already does) or make discovery asynchronous, with an explicit refresh/invalidation policy.
    const availability = resolveLocalDelegationAvailability();

extensions/signals-dashboard/extension.mjs:805

  • This is a stateful toggle, but its accessible name exposes only the next action and no programmatic pressed state; screen-reader users cannot distinguish Off, requested-On-but-unavailable, and effective-On, since title is not a reliable accessible description. Expose the preference via aria-pressed and include the effective/availability text in the accessible name or description.
        <button data-act="local-delegation" data-preference="${esc(next)}"
            aria-label="Set Local Delegation ${esc(next)}"
            style="background:#020617;border:1px solid ${border};color:${color};padding:2px 8px;border-radius:999px;

Copilot AI review requested due to automatic review settings August 14, 2026 19:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (3)

extensions/signals-dashboard/extension.mjs:382

  • writeFile follows an existing .local-delegation.json symlink. A workshop repository can therefore contain a planted symlink, and clicking the new toggle will truncate and overwrite an arbitrary writable file outside the workshop. Write to a newly created temporary file in the workshop and atomically rename it over the state path (with cleanup/concurrency handling), so the destination symlink itself is replaced rather than followed.
    await writeFile(
        join(workshopDir, LOCAL_DELEGATION_STATE_FILE),
        JSON.stringify(state, null, 2) + "\n",
        "utf8");

extensions/signals-dashboard/extension.mjs:1161

  • When terminal launch fails and Local Delegation was requested but unavailable, localDetail replaces path. If clipboard access also fails, the toast says “copy this path” but never displays the path, removing the only fallback handle. Keep the path in the detail and append the delegation warning instead of replacing it.
                    showToast(copyTitle + localTitle, localDetail || path);

extensions/signals-dashboard/README.md:110

  • The linked source implementation also adds .local-delegation.json to the workshop .gitignore, but this port writes the runtime preference at the repository root without adding an equivalent ignore rule to the Workshop scaffolding. Toggling Local in a Git-backed workshop created by this plugin will leave operator runtime state untracked and easy to commit accidentally. Update the workshop creation guidance/scaffold (and existing-workshop guidance) to ignore this file.
Operator preference is stored at the workshop root in `.local-delegation.json`.

- Cross-platform path.join in receipt fixture
- Atomic .local-delegation.json write (no symlink follow)
- Case-insensitive WORKSHOP_LOCAL_DELEGATION env clear
- Windows Terminal: set/clear env via cmd before agent
- aria-pressed on Local toggle

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 19:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

extensions/signals-dashboard/extension.mjs:439

  • This safety check also examines the --add-dir workshop path and resolved executable path, not just untrusted desk input. Valid Windows locations such as C:\Work (Local) or C:\R&D\Workshop therefore make cmdSafe false and every desk open falls back instead of launching. Preserve support for quoted metacharacters in trusted paths while still preventing cmd expansion/injection.
        const cmdSafe = run.every((arg) => !/[&|<>^%!()\r\n]/.test(arg))
            && run.every((arg) => isSafeWindowsCmdShim(arg));
        if (!cmdSafe || !cmd) return false;

extensions/signals-dashboard/extension.mjs:1180

  • When a terminal launch fails while Local Delegation was requested but unavailable, localDetail contains the availability reason and replaces path. The toast then says “copy this path” but never displays the path, defeating the manual fallback when clipboard access also failed. Include both the path and the Local Delegation detail in this branch.
                    const copyTitle = copied ? (name + ' · path copied') : (name + ' · copy this path');
                    showToast(copyTitle + localTitle, localDetail || path);

Comment thread extensions/signals-dashboard/extension.mjs Outdated
…hop repo

A cloned workshop must not be able to ship preference:on. Key operator intent
under ~/.copilot/workshop-local-delegation/ by canonical workshop path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 19:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

extensions/signals-dashboard/extension.mjs:1517

  • This description still says the toggle defaults from .local-delegation.json, but the implementation now deliberately ignores repo-root state and reads the hashed user-local file under ~/.copilot/workshop-local-delegation/. Update the action contract so callers are not directed to a rejected state file.
                                description: "Optional Local Delegation preference for this launch. Defaults to the workshop Cairn toggle (.local-delegation.json).",

extensions/signals-dashboard/local-delegation.mjs:207

  • The dashboard refreshes every five seconds, and each render recomputes availability, so when the skill is absent this synchronous scan walks every installed marketplace and plugin and probes four paths per plugin on every refresh. That blocks the loopback server's event loop and scales with the user's entire plugin inventory. Cache skill discovery (including a negative result) for a bounded TTL while continuing to re-check the lightweight route receipt.
    if (exists(pluginsRoot)) {
        try {
            for (const market of readdirSync(pluginsRoot, { withFileTypes: true })) {

Comment thread extensions/signals-dashboard/local-delegation.mjs Outdated
Lowercasing collided distinct workshops on case-sensitive filesystems.
Normalize separators only; realpath already supplies a stable path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

extensions/signals-dashboard/extension.mjs:1517

  • This tool description still says the toggle defaults from .local-delegation.json, but this change deliberately ignores repository-root state and stores the preference under ~/.copilot/workshop-local-delegation/. The stale schema text can direct callers to the rejected file and contradicts the new fail-closed storage model.
                                description: "Optional Local Delegation preference for this launch. Defaults to the workshop Cairn toggle (.local-delegation.json).",

Comment thread extensions/signals-dashboard/extension.mjs Outdated
Args are quote-wrapped; only block % and ! expanders inside quotes so paths
like C:\Work\Project (1) still launch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
Copilot AI review requested due to automatic review settings August 14, 2026 19:49
Complete the parentheses fix: use isSafeQuotedWindowsCmdArg for cmdSafe.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

extensions/signals-dashboard/extension.mjs:1518

  • This API description points consumers to .local-delegation.json, but the implementation now deliberately ignores repo-root state and reads the hashed user-local preference under ~/.copilot/workshop-local-delegation/. Update the schema text so agents do not create or rely on a file that has no effect.
                                enum: ["off", "on"],

extensions/signals-dashboard/extension.mjs:831

  • When the preference is on but availability fails, the accessible name becomes Local Delegation On*; the asterisk has no accessible explanation and incorrectly sounds effective to screen-reader users. Include the requested-but-unavailable state and reason in the button's accessible name.
        <button data-act="local-delegation" data-preference="${esc(next)}"

Comment thread extensions/signals-dashboard/extension.mjs Outdated
Copilot AI review requested due to automatic review settings August 14, 2026 19:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (1)

extensions/signals-dashboard/extension.mjs:1519

  • This tool description still says the default comes from .local-delegation.json, but the implementation now explicitly ignores repo-root state and reads the user-local hashed preference under ~/.copilot/workshop-local-delegation/. Since this schema is exposed to the agent, it can direct callers toward a file that has no effect and contradicts the fail-closed storage model. Describe the user-local Cairn preference instead.
                                description: "Optional Local Delegation preference for this launch. Defaults to the workshop Cairn toggle (.local-delegation.json).",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

canvas-extension PR touches canvas extensions needs-review:HIGH Contributor reputation check flagged HIGH risk plugin PR touches plugins

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants