Skip to content

feat: Deploy scaffolding, PTY system terminal and AI transcript fixes#142

Merged
nfebe merged 7 commits into
mainfrom
feat/issue-138-improvements
Jun 8, 2026
Merged

feat: Deploy scaffolding, PTY system terminal and AI transcript fixes#142
nfebe merged 7 commits into
mainfrom
feat/issue-138-improvements

Conversation

@nfebe

@nfebe nfebe commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Image and compose deploys can select an app template: the user's image or compose content is kept while the template contributes container port, bind mount defaults, pre-created directories, ownership and a generated environment file (preferring the image's own env example, with per-deployment secrets such as APP_KEY). Required mounts apply by default; explicit selections override them.
  • On-disk template copies now sync with the binary's embedded set, so agent upgrades take effect without a manual refresh.
  • The file manager's hidden-files default is a persisted setting exposed through the config API (default: shown).
  • The system terminal runs the host shell on a real PTY over a websocket, with the container-exec stream protocol, per-line protected-command enforcement and the global disable honored. The JSON endpoint stays for programmatic use.
  • Prompts composed by the product (log analysis, operation diagnosis) no longer appear in the assistant transcript; the model still receives them.
  • e2e harness aborts loudly on leftover root-owned state instead of failing unrelated tests.
  • Version 0.3.0.

Closes #137, closes #138.

Notes

nfebe added 7 commits June 8, 2026 00:15
The file manager's hidden files default is now a persisted agent
setting exposed through the key based config API. It defaults to
enabled, and an explicit off choice survives agent restarts.
Deployments created from a custom image can now reference an app
template. The user's image is kept while the template contributes its
default container port and bind mounts; required mounts are included
when no explicit selection is made. Combined with the existing template
scaffolding, image and compose deploys get pre-created directories,
default environment files and correct ownership.
Deployments created from a custom image or compose file can now select
an app template. The user's image and compose content are kept while the
template contributes its container port, default bind mounts,
pre-created directories and ownership. Required mounts apply by default
and explicit selections override them entirely.

Templates can also declare how a platform's environment file is
produced: preferring the example shipped inside the deployed image,
falling back to template-provided content, generating fresh secrets per
deployment and filling in database credentials. The Laravel template
uses this for its environment file, full storage directory tree and
bootstrap cache.

Bind mounts can declare their host path, single-file mounts stay files,
and ownership is applied recursively so nested directories belong to
the container user. On-disk template copies are refreshed whenever the
binary's embedded set changes, so upgrades take effect without a manual
refresh.
Entry points that open the assistant with a canned prompt (log
analysis, operation diagnosis) no longer show that prompt as if the
operator typed it. The model still receives the full prompt and its
context; the visible conversation starts with the assistant's answer.
Only messages the operator actually types are displayed.
The agent container runs as root and leaves root-owned files in the
shared test directories. Teardown could not remove them and the next
run silently started on stale state, failing unrelated tests in
confusing ways. The suite now refuses to start until the leftover
directories are removed.
The system terminal could not run anything that needs a tty:
terminal-control commands (reset, tput, stty) failed and full-screen
interactive programs (top, htop, vim, less, watch) had no way to
receive keystrokes. A new interactive websocket endpoint runs the host
shell under a PTY with the same stream protocol as the container
terminal: binary frames for raw bytes, JSON text frames for resizes,
first-message token auth.

Global protected command rules are enforced per submitted line; a
blocked line is cancelled and the operator notified. Disabling the
terminal through global protected mode is honored. The JSON command
endpoint stays unchanged as the programmatic surface.

Closes #137
@sourceant

sourceant Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code Review Summary

This PR introduces version 0.3.0 with significant enhancements to deployment scaffolding, a new interactive system PTY, and improved AI session handling.

🚀 Key Improvements

  • New interactive system terminal using WebSockets and PTY with command guarding.
  • Sophisticated environment file generation for templates, including secret generation (APP_KEY, etc.) and extraction of .env.example from images.
  • Automatic synchronization of on-disk templates with embedded assets using checksums.
  • Hidden AI messages to support 'behind-the-scenes' product-led log analysis.

💡 Minor Suggestions

  • Correct modulo bias in alphanumeric secret generation.
  • Use Lchown instead of Chown during recursive directory processing to prevent symlink attacks.

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Comment thread internal/api/server.go
case "alphanumeric":
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
out := make([]byte, n)
for i, b := range buf {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using int(b) % len(charset) introduces a modulo bias because 256 is not a multiple of 62. This makes some characters slightly more likely to appear than others. For cryptographic secrets, consider using a rejection sampling method or a larger power-of-two charset.

Suggested change
for i, b := range buf {
for i := 0; i < n; i++ {
out[i] = charset[int(buf[i])%len(charset)] // Consider rejection sampling for absolute uniformity
}

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.

Important improvements System terminal: run a real PTY instead of emulating a terminal

1 participant