Skip to content

Add help50 integration - #196

Merged
rongxin-liu merged 3 commits into
canaryfrom
help50-canary
Sep 21, 2026
Merged

rongxin-liu merged 3 commits into
canaryfrom
help50-canary

Conversation

@rongxin-liu

Copy link
Copy Markdown
Contributor

Wires the new help50 from cs50/cli#210 into the codespace, so a failed command in the terminal can hand its error to the CS50 Duck. Targets canary to test on the canary image.

How it works

/etc/profile.d/help50.sh (from cs50/cli) runs after each command and calls one of three hooks. codespace.sh now overrides them:

  • _helpful (a local helper had advice, e.g. 1s -> "Did you mean ls?"): prints the advice in the terminal as before, and shows a help50 button in the terminal title bar; clicking it has the duck say the same advice, so the student can follow up.
  • _helpless (no helper matched): prints "Click help50 above for help with that error" and shows the button; clicking it sends the output to cs50.ai for an explanation. Skipped when the command produced no output, so grep with no match, false, or a program exiting 1 stay quiet.
  • _helped (command succeeded): hides the button, only if one is showing.

The button is the help50 extension (cs50/help50.vsix#1); the shell reaches it through command50, the same bridge style50 uses. command50 runs detached with output discarded, so the prompt is never delayed and a missing extension server degrades silently.

Other changes

  • WORKDIR is set to /workspaces/$RepositoryName. cs50/cli defaults it to $HOME, so help50's "Did you mean to cd foo/bar first?" suggestions never fired in codespaces.
  • help50.vsix is built into /opt/cs50/extensions and installed like the other extensions.
  • A Sysadmins terminal profile (sudo bash) gives staff a root shell, which cs50/cli's profile skips entirely, so no help50.
  • tests/smoke.sh runs the built image under timeouts and is run in CI after each build, before any push: non-interactive login shells exit, the hooks are the codespace overrides and behave, help50.vsix and command50 are present, root shells have no help50.

Testing

Overlaid codespace.sh on cs50/cli with a fake command50 that logs its arguments and drove an interactive login shell under a pty. 1s, python baz.py from the wrong directory, and cat nothere produced the expected inline text and exactly one showButton call each with the message intact; true/ls produced one hideButton each; grep with no match, false, and diff produced nothing. tests/smoke.sh passes on that image.

Depends on the current default branches of cs50/help50.vsix and cs50/cs50.vsix (both merged today) and on cs50/cli:canary carrying the help50 branch.

- codespace.sh: override help50's _helpful/_helpless/_helped hooks to relay to
  the help50 extension via command50, which shows a button in the terminal
  title bar that hands the message to the CS50 Duck; skip _helpless when the
  failed command produced no output (e.g., grep with no match)
- codespace.sh: set WORKDIR to the workspace so help50's helpers can find
  misplaced files (cs50/cli defaults it to $HOME)
- Dockerfile, devcontainer.json: build and install help50.vsix
- devcontainer.json: add a Sysadmins terminal profile (sudo bash), which
  gets a root shell without help50
tests/smoke.sh runs the built image under timeouts: non-interactive login
shells exit (help50 must not start without a terminal), the help50 hooks
are the codespace overrides and behave, help50.vsix and command50 are
present, and root shells have no help50. Run in CI after each build and
before any push.
Branch builds use cs50/cli:amd64 (main), which doesn't have help50 yet, so
codespace.sh errored on every login shell sourcing /opt/cs50/lib/cli. Guard
the source, and have the smoke test skip the help50 checks (visibly) when the
base image lacks them, while still asserting that login shells start cleanly.
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