Skip to content

feat: desktop terminal-action bridge (Push, Add datasource, New project) - #15

Closed
ElfredSeow wants to merge 24 commits into
feat/strengthen-the-PRDfrom
feat/desktop-terminal-action-bridge
Closed

feat: desktop terminal-action bridge (Push, Add datasource, New project)#15
ElfredSeow wants to merge 24 commits into
feat/strengthen-the-PRDfrom
feat/desktop-terminal-action-bridge

Conversation

@ElfredSeow

Copy link
Copy Markdown
Collaborator

Summary

Bridges three terminal actions into the chat/desktop UI, each reachable via both a toolbar button and a typed chat request:

  • 🚀 Pushnpm run build (if present) then pac code push
  • 🧩 Add datasourcepac code add-data-source, with a picker for already-created Dataverse tables
  • ✨ New project — the full PowerCodex scaffold (starter template + OpenSpec + all OPSX prompts/skills + git init), created in a folder you pick and switched to automatically

Push and Add datasource are gated on the existing allowPush consent flag (Approved_rights/approval.json) — off by default, enforced independently on both the button path (Controller.action()) and the chat path (agent.js). New project has no gate (local-only scaffolding).

Design spec: docs/superpowers/specs/2026-07-13-desktop-terminal-action-bridge-design.md
Implementation plan: docs/superpowers/plans/2026-07-13-desktop-terminal-action-bridge.md

Why stacked on feat/strengthen-the-PRD

This branch reuses the pac CLI wiring (pac-init.js) landed in PR #14, which isn't on main yet.

Notable fixes found during review

  • A packaging gap: the desktop app's build only vendored templates/starter, not bin/create-powercodex.js or the rest of templates/, so "New project" would have silently failed once packaged (not just in a repo checkout). Fixed in desktop/scripts/sync-lifecycle.js.
  • A Critical pair in the chat UI commit: a stray straight apostrophe broke the entire inline <script> tag's parse, and two new handlers concatenated user input (a free-text connector id, a project name from prompt()) unescaped into an innerHTML sink — both fixed and covered by new regression checks (including a check that actually parses the script).
  • The chat-intent regex for "push"/"deploy"/"publish" was originally too broad (misfired on "push back on this") and then too narrow (rejected "publish this"); both fixed. A similar over-broad match on "create a new project" that hijacked ordinary sentences merely containing the word "project" was caught in final review and tightened.
  • The plan's own test code for the new-project route would have spawned a real npm install on every npm run lifecycle:selftest run — fixed to fail fast before any spawn.

Test plan

  • npm run lifecycle:selftest — 215/215 checks passing (up from 160 baseline)
  • Every tools/lifecycle/ file change mirrored byte-identically to templates/starter/tools/lifecycle/ (verified via diff)
  • Full whole-branch code review (opus) — all Critical/Important findings fixed
  • Manual: cd desktop && npm start, click "✨ New project" end-to-end in a real Electron window (no display was available in this session — flagged as a follow-up before/at merge)

🤖 Generated with Claude Code

ElfredSeow and others added 24 commits July 13, 2026 16:12
Push / Add-datasource / Create-new-project buttons + chat intents,
all routed through Controller.action() so button and chat share one
implementation per action.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
9 tasks: buildAndPush, datasource.js, scaffold-cli.js, chat.js intent
routing, control.js + agent.js wiring, server.js routing, chat.html UI,
and a desktop vendoring fix so New Project works in the packaged app
(not just dev mode).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implements buildAndPush() to run npm run build (when present) followed
by pac code push. Also exports runPac as an alias for pac() so datasource.js
can spawn pac without duplicating binary-resolution logic.

New functions:
- buildAndPush(root, { appDir, emit, _push }) — orchestrate build+push
- hasBuildScript(root) — check if package.json has a build script
- runNpmBuild(root, { emit }) — execute npm run build

Adds 4 selftest checks covering successful build with push, build failure,
and skipping build when no script exists.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.superpowers/ is the subagent-driven-development progress ledger
(git-ignored scratch). package-lock.json changes are npm normalizing
stray "peer": true markers on install — unrelated to any task.
Implements the datasource module wrapping pac code add-data-source for wiring
Dataverse tables and connectors into Code App power.config.json. Includes
comprehensive test coverage via selftest.js checks for api validation, flag
construction, and error handling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ion paths

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…resolution

- Sanitize the 'name' parameter in scaffoldNewProject() to prevent path-traversal
- Add selftest check for binPath() real two-candidate resolution
- Add selftest check for path-traversal-shaped name sanitization
- Mirror changes to starter template

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… not substring

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…loy phrasing

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sh and deploy do

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add case 'push': gated on allowPush, calls pacInit.buildAndPush()
- Add case 'add-datasource': gated on allowPush, calls addDataSource()
- Both emit progress to the dashboard and return ok/error appropriately
- Add test checks in selftest.js to verify gating and reachability

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…assertion

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…xtraction; revert out-of-scope AGENT_SYSTEM edit

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 6's fix subagent claimed this was already reverted but the
working tree still carried escaped-straight-quote apostrophes,
outside that task's declared scope (run() + top-level requires only).
…oint

Task 7: scaffoldProject() closure function spawns Task 3's scaffoldNewProject()
then switches workspace via openProject(); POST /api/action with type:scaffold-project
routing; /api/agent post-processing for agent.run()'s kind:scaffold-project result;
GET /api/dataverse-state for the Add-datasource picker (Task 8).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…real npm install

The scaffoldProject route now tests its failure path directly by passing a
non-existent targetDir. This causes scaffoldProject()'s own fs.statSync check
to fail fast with "That folder no longer exists," before ever reaching
scaffoldCli.scaffoldNewProject()—so the real bin/create-powercodex.js is never
spawned, preventing network calls and global npm state mutation. The test runs
in seconds instead of 8+ seconds waiting on npm install.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…aching innerHTML

- Replace straight apostrophe in "It's ready to build" with curly quote (U+2019) to fix JS parse error in newProjectBtn handler
- Escape user-controlled table and connector names in dsGo handler before passing to innerHTML (XSS fix)
- Escape user-supplied project name in newProjectBtn handler before passing to innerHTML (XSS fix)
- Add regression check to validate inline script parses without syntax errors

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…w project works in the packaged app

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…roject", not just anywhere in the message

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ElfredSeow ElfredSeow closed this Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant