propr-cli 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,6 +60,42 @@ and exits nonzero when required local stack prerequisites are missing. Scripts
60
60
  or shell integrations that invoked bare `propr` to print help text should call
61
61
  `propr --help` instead.
62
62
 
63
+ ## Hosted UI Tunnel
64
+
65
+ ProPR Connect can provision a managed Cloudflare Tunnel so the hosted UI at
66
+ `https://app.propr.dev` can reach your local stack's API. Run the one-time setup
67
+ command shown in ProPR Connect from your initialized stack directory:
68
+
69
+ ```bash
70
+ npm install -g propr-cli@latest
71
+ propr tunnel setup --token <connector-token> --url https://t-<id>.propr.dev --start
72
+ ```
73
+
74
+ Connect-managed tunnels require `propr-cli` 0.8.6 or newer. The setup command
75
+ writes the tunnel token, instance id, hosted UI origin, public API URL, and
76
+ OAuth callback URL to the stack `.env`, records tunnel mode as enabled, and with
77
+ `--start` starts or recreates the stack so the API picks up the hosted URLs
78
+ immediately. If you have only the instance id, `--instance-id <id>` derives the
79
+ same public URL.
80
+
81
+ The public tunnel origin is always a bare `https://t-<id>.propr.dev` URL; ProPR
82
+ routes only `/api/*` and `/socket.io/*` through it, and the root URL
83
+ intentionally returns 404. The hosted UI itself stays on `https://app.propr.dev`
84
+ and calls the API through the per-instance tunnel host.
85
+
86
+ Useful follow-up commands:
87
+
88
+ ```bash
89
+ propr tunnel verify # check cloudflared + /api/status, /, /socket.io/
90
+ propr tunnel off # stop only the sidecar; token/env values stay in .env
91
+ propr tunnel on # restart the sidecar later
92
+ ```
93
+
94
+ `propr tunnel off` intentionally leaves the Connect-written `.env` values in
95
+ place. If you are switching the same stack back to a local or custom self-hosted
96
+ UI, remove or replace `PROPR_UI_PUBLIC_API_URL`, `API_PUBLIC_URL`,
97
+ `FRONTEND_URL`, and `GH_OAUTH_CALLBACK_URL` before restarting.
98
+
63
99
  ## Repository Setup
64
100
 
65
101
  Use `propr init` from a repository root to scaffold `.propr` setup files used by agent execution containers.
@@ -0,0 +1,183 @@
1
+ # GitHub App Configuration
2
+ GH_APP_ID=your_app_id
3
+ GH_PRIVATE_KEY_PATH=./path/to/your-app-private-key.pem
4
+ GH_INSTALLATION_ID=your_installation_id
5
+
6
+ # Host path to the GitHub App private key (.pem). Recommended when running via
7
+ # the `propr` CLI or launcher: the key is bind-mounted (read-only) into the app
8
+ # containers and GH_PRIVATE_KEY_PATH above is overridden to point at it, so you
9
+ # can keep the key anywhere on the host instead of staging it under data/.
10
+ # Must be an absolute host path (no '~').
11
+ # HOST_GH_PRIVATE_KEY=/home/your-user/propr/app-private-key.pem
12
+
13
+ # GitHub auth: token relay (shared-app path) — ALTERNATIVE to the App private key
14
+ # above. When PROPR_GH_RELAY_URL is set, the backend fetches short-lived
15
+ # installation tokens from a vendor-run relay instead of minting them from a
16
+ # private key, so you don't need to hold the shared App's key. You still set
17
+ # GH_INSTALLATION_ID (which installation), but GH_PRIVATE_KEY_PATH /
18
+ # HOST_GH_PRIVATE_KEY are not required in relay mode.
19
+ # PROPR_GH_RELAY_URL — https URL of the relay (http only allowed for localhost)
20
+ # PROPR_GH_RELAY_TOKEN — the durable relay credential issued for your install
21
+ # PROPR_GH_RELAY_URL=https://relay.propr.dev
22
+ # PROPR_GH_RELAY_TOKEN=your_relay_token
23
+ # Optional: force a mode explicitly instead of inferring (app | relay | demo).
24
+ # GH_AUTH_MODE=relay
25
+
26
+ # Logging Configuration
27
+ LOG_LEVEL=info
28
+ NODE_ENV=development
29
+
30
+ # Daemon Configuration
31
+ GITHUB_REPOS_TO_MONITOR=owner/repo1,owner/repo2
32
+ POLLING_INTERVAL_MS=60000
33
+
34
+ # Config Repository (for dynamic repository management)
35
+ CONFIG_REPO=https://github.com/integry/gitfix-config.git
36
+
37
+ # Issue Detection Configuration
38
+ PRIMARY_PROCESSING_LABELS=AI,propr
39
+ PR_LABEL=propr
40
+
41
+ # Redis Configuration
42
+ REDIS_HOST=127.0.0.1
43
+ REDIS_PORT=6379
44
+
45
+ # Queue Configuration
46
+ GITHUB_ISSUE_QUEUE_NAME=github-issue-processor
47
+ WORKER_CONCURRENCY=2
48
+ COMMENT_BATCH_DELAY_MS=3000
49
+
50
+ # Webhook Configuration
51
+ # Webhooks are received by the dashboard API service (port 4000)
52
+ ENABLE_GITHUB_WEBHOOKS=false
53
+ GH_WEBHOOK_SECRET=your-webhook-secret
54
+
55
+ # System Task Authorization
56
+ # Secret used to sign system task requests (e.g., revert operations)
57
+ # Generate with: openssl rand -hex 32
58
+ SYSTEM_TASK_SECRET=
59
+ # Maximum age (ms) for signed system task tokens. Increase if jobs frequently expire
60
+ # due to queue backlog or worker downtime. Defaults to 7200000 (2 hours).
61
+ # SYSTEM_TASK_TOKEN_MAX_AGE_MS=7200000
62
+
63
+ # Worker Configuration
64
+
65
+ # PR Comment Monitoring Configuration
66
+ GITHUB_BOT_USERNAME=your_bot_username
67
+ GITHUB_USER_WHITELIST=
68
+ GITHUB_USER_BLACKLIST=
69
+ PR_FOLLOWUP_TRIGGER_KEYWORDS=!propr
70
+
71
+ # Git Configuration
72
+ GIT_CLONES_BASE_PATH=/tmp/git-processor/clones
73
+ GIT_WORKTREES_BASE_PATH=/tmp/git-processor/worktrees
74
+ GIT_DEFAULT_BRANCH=main
75
+ GIT_SHALLOW_CLONE_DEPTH=
76
+
77
+ # Claude Code Configuration
78
+ CLAUDE_DOCKER_IMAGE=propr/agent-claude:latest
79
+ # Must be an absolute path — do NOT use ~ or ${HOME} (neither is expanded in
80
+ # .env files parsed by Node or in Docker bind mounts).
81
+ # CLAUDE_CONFIG_PATH=/home/your-user/.claude
82
+ CLAUDE_CONFIG_PATH=
83
+ CLAUDE_MAX_TURNS=10
84
+ CLAUDE_TIMEOUT_MS=300000
85
+ CODEX_TIMEOUT_MS=3600000
86
+
87
+ # Antigravity Configuration
88
+ ANTIGRAVITY_TIMEOUT_MS=300000
89
+
90
+ # OpenCode Configuration
91
+ OPENCODE_TIMEOUT_MS=3600000
92
+ # Launcher credential mount paths (required when using docker/launcher).
93
+ # HOST_OPENCODE_XDG_DIR points to the XDG config directory
94
+ # (/home/your-user/.config/opencode)
95
+ # and takes precedence over HOST_OPENCODE_DIR.
96
+ # HOST_OPENCODE_DIR is accepted as a fallback alias for HOST_OPENCODE_XDG_DIR.
97
+ # HOST_OPENCODE_LEGACY_DIR points to the legacy /home/your-user/.opencode directory.
98
+ # The saved agent configPath still controls the runtime mount; the launcher
99
+ # sets OPENCODE_CONFIG_PATH only as the default path for worker/API processes.
100
+ # HOST_OPENCODE_DATA_DIR points to normal opencode auth data
101
+ # (/home/your-user/.local/share/opencode). Set it for launcher deployments
102
+ # so normal `opencode auth login` credentials are visible to spawned OpenCode
103
+ # agent containers and can refresh auth metadata when required.
104
+ # HOST_OPENCODE_XDG_DIR=/home/your-user/.config/opencode
105
+ # HOST_OPENCODE_DIR=/home/your-user/.config/opencode
106
+ # HOST_OPENCODE_LEGACY_DIR=/home/your-user/.opencode
107
+ # HOST_OPENCODE_DATA_DIR=/home/your-user/.local/share/opencode
108
+
109
+ # --- Mistral Vibe Configuration (only required when using a Vibe agent) ---
110
+ # Must be an absolute path — do NOT use ~ or ${HOME} (see CLAUDE_CONFIG_PATH note).
111
+ # VIBE_CONFIG_PATH=/home/your-user/.vibe
112
+ # Used when VIBE_CONFIG_PATH does not provide credentials.
113
+ # MISTRAL_API_KEY=
114
+ VIBE_MAX_TURNS=1000
115
+ VIBE_TIMEOUT_MS=3600000
116
+ # Production launcher only — host paths for mounting agent credential directories
117
+ # into containers. Omit any HOST_*_DIR to skip mounts for that agent.
118
+ # All HOST_*_DIR values MUST be absolute paths (no ~ or relative paths).
119
+ # HOST_CLAUDE_DIR=/home/your-user/.claude
120
+ # HOST_CODEX_DIR=/home/your-user/.codex
121
+ # HOST_ANTIGRAVITY_DIR=/home/your-user/.antigravity
122
+ # HOST_VIBE_DIR=/home/your-user/.vibe
123
+ # Required for Vibe Docker-outside-Docker: prompt files must be written to a
124
+ # host-visible directory so spawned agent containers can bind-mount them.
125
+ # Both should reference the same host path.
126
+ # NOTE: These are required whenever Vibe agents are used with the launcher
127
+ # (i.e. when MISTRAL_API_KEY is set), not only when HOST_VIBE_DIR is set.
128
+ # Create the directory before starting: mkdir -p /tmp/propr-vibe-prompts
129
+ # VIBE_PROMPT_CACHE_DIR=/tmp/propr-vibe-prompts
130
+ # HOST_VIBE_PROMPT_CACHE_DIR=/tmp/propr-vibe-prompts
131
+
132
+ # Dashboard API Configuration
133
+ DASHBOARD_API_PORT=4000
134
+ # Required in normal and demo mode for auth redirects.
135
+ FRONTEND_URL=http://localhost:5173
136
+ # Optional comma-separated redirect hosts for auth preview flows.
137
+ # Entries are exact host matches by default. Prefix with "." or "*." only for
138
+ # parent domains where every subdomain is trusted, for example .preview.example.com.
139
+ # FRONTEND_URL is exact-only; COOKIE_DOMAIN allows subdomains when it starts with ".".
140
+ # AUTH_REDIRECT_ALLOWED_HOSTS=preview.example.com
141
+
142
+ # GitHub OAuth Configuration
143
+ GH_OAUTH_CLIENT_ID=your_github_oauth_client_id
144
+ GH_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret
145
+ GH_OAUTH_CALLBACK_URL=http://localhost:4000/api/auth/github/callback
146
+ SESSION_SECRET=your-session-secret-here
147
+
148
+ # Bearer Token Authentication (CLI)
149
+ # Set to 'false' to disable Bearer token auth and only allow session-based login
150
+ ENABLE_BEARER_AUTH=true
151
+
152
+ # Demo Mode
153
+ # Set to 'true' or '1' to allow read-only access without GitHub OAuth and block all mutating API requests.
154
+ # Public demo deployments should use a curated config/database.
155
+ PROPR_DEMO_MODE=false
156
+
157
+ # --- SQLite Database ---
158
+ # Path to SQLite database file (will be created if it doesn't exist)
159
+ DB_FILENAME=./data/propr.sqlite
160
+
161
+ # --- PR Preview Environment ---
162
+ # Path to staging .env file (provides base configuration for PR previews)
163
+ # PR-specific values (ports, API URLs) are passed as inline overrides
164
+ STAGING_ENV_FILE=/path/to/staging/.env
165
+
166
+ # Path to staging database file for seeding PR preview environments
167
+ STAGING_DB_PATH=/path/to/staging/data/propr.sqlite
168
+
169
+ # Enable preview environment routing (routes webhooks to PR preview instances)
170
+ ENABLE_PREVIEW_ROUTING=false
171
+
172
+ # The ProPR repository in 'owner/repo' format. Label events from this repo
173
+ # trigger processor assignment changes. Defaults to 'integry/propr'.
174
+ PROPR_REPO=integry/propr
175
+
176
+ # The label that designates a ProPR PR as the active processor for webhook routing.
177
+ # When this label is added to a ProPR repo PR, that PR's preview instance becomes
178
+ # the active processor. Defaults to 'preview-env'.
179
+ PROCESSOR_LABEL=preview-env
180
+
181
+ # Host address for forwarding webhooks to PR preview instances.
182
+ # Defaults to 'http://host.docker.internal' for Docker environments.
183
+ # HOST_GATEWAY_ADDRESS=http://host.docker.internal
@@ -31,6 +31,9 @@ GITHUB_EVENT_INTAKE_MODE=routing_websocket
31
31
  # only need them below to point at a self-hosted relay.
32
32
  # PROPR_ROUTING_URL=wss://webhook.propr.dev
33
33
  # PROPR_GH_RELAY_URL=https://webhook.propr.dev/v1
34
+ # Optional transport keepalive override. The default is 300000 ms (5 minutes);
35
+ # lower it only if a network path closes otherwise-healthy WebSockets too quickly.
36
+ # PROPR_ROUTING_WS_PING_INTERVAL_MS=300000
34
37
  # Per-install secrets — left commented so an unedited copy is not mistaken for a
35
38
  # configured relay. Run `propr relay enroll` to fill these in, or uncomment and set
36
39
  # them by hand. (Active placeholder values here could make intake/auth mode look
@@ -42,6 +45,70 @@ GITHUB_EVENT_INTAKE_MODE=routing_websocket
42
45
  # are set, so you normally do not need this.
43
46
  # GH_AUTH_MODE=relay
44
47
 
48
+ # --- Hosted UI tunnel (v1, optional) -----------------------------------------
49
+ # Expose this local stack's API to the hosted control plane at
50
+ # https://app.propr.dev through a Cloudflare Tunnel, so you can drive a
51
+ # locally-running stack from the hosted UI. The tunnel publishes the API
52
+ # container (only /api/* and /socket.io/* are routed; the root URL returns 404);
53
+ # the UI bundle is served by app.propr.dev, not through the tunnel. Cloudflare
54
+ # forwards the tunnel to the Docker-internal http://api:4000, NOT host port 4000,
55
+ # so the published host port is irrelevant to the tunnel and cannot conflict with
56
+ # it. Off by default; local development is unaffected (API_PUBLIC_URL /
57
+ # FRONTEND_URL keep their localhost defaults below).
58
+ #
59
+ # Normal setup is CLI-first: ProPR Connect shows a one-time command such as
60
+ # `propr tunnel setup --token ... --url https://<id>.proxy.propr.dev --start`.
61
+ # Run that from this stack directory so the CLI writes these values and restarts
62
+ # the stack for you. The variables below are documented as a fallback for older
63
+ # CLI versions, manual recovery, or auditing what the setup command persists.
64
+ #
65
+ # Enable the tunnel:
66
+ # PROPR_UI_TUNNEL_TOKEN — Cloudflare Tunnel token; required to start. Setting it
67
+ # enables the tunnel by default, so the next `propr start`
68
+ # brings up the sidecar (unless you ran `propr tunnel off`).
69
+ # WARNING: this is a LIVE Cloudflare credential — anyone
70
+ # with it can route traffic through your tunnel. Do not
71
+ # commit, log, or share it; keep it in this .env only.
72
+ # PROPR_UI_TUNNEL_ENABLED — explicitly enable the tunnel (`true`/`1`). A token is
73
+ # STILL required — `propr check` fails if this is set
74
+ # without PROPR_UI_TUNNEL_TOKEN. Redundant when a token
75
+ # is set, since a token alone already enables the tunnel
76
+ # PROPR_INSTANCE_ID — this stack's instance id; must be a valid DNS label
77
+ # (letters, digits, hyphens; 1-63 chars). Derives the
78
+ # public URL https://<id>.proxy.propr.dev when no
79
+ # explicit URL is set
80
+ # PROPR_UI_PUBLIC_API_URL — explicit public API URL the hosted UI talks to (overrides the derived one)
81
+ # PROPR_CLOUDFLARED_IMAGE — cloudflared image (default: cloudflare/cloudflared:2024.12.2,
82
+ # a pinned tag; override only if you need a different build)
83
+ # PROPR_UI_TUNNEL_TOKEN=your_cloudflare_tunnel_token
84
+ # PROPR_INSTANCE_ID=abc123
85
+ # PROPR_UI_PUBLIC_API_URL=https://abc123.proxy.propr.dev
86
+ # PROPR_CLOUDFLARED_IMAGE=cloudflare/cloudflared:2024.12.2
87
+ #
88
+ # Why `.proxy.propr.dev`: each enabled stack is published under a per-instance
89
+ # hostname `<PROPR_INSTANCE_ID>.proxy.propr.dev`. The hosted UI at
90
+ # https://app.propr.dev discovers and reaches your stack's API through that
91
+ # single shared suffix, without you owning or registering a domain.
92
+ #
93
+ # Browser origin vs API host — they are DIFFERENT and must be set accordingly.
94
+ # The browser loads the UI from app.propr.dev; the API, Socket.IO, OAuth
95
+ # callback, and session cookie all live on the proxy host. In tunnel mode
96
+ # FRONTEND_URL, API_PUBLIC_URL, and GH_OAUTH_CALLBACK_URL are derived
97
+ # automatically (FRONTEND_URL -> https://app.propr.dev, API_PUBLIC_URL -> the
98
+ # proxy host, GH_OAUTH_CALLBACK_URL -> <proxy host>/api/auth/github/callback);
99
+ # set them only to override. You must still register the callback URL — derived
100
+ # or explicit — in your GitHub OAuth App.
101
+ # FRONTEND_URL=https://app.propr.dev
102
+ # API_PUBLIC_URL=https://abc123.proxy.propr.dev
103
+ # GH_OAUTH_CALLBACK_URL=https://abc123.proxy.propr.dev/api/auth/github/callback
104
+ #
105
+ # COOKIE_DOMAIN: leave UNSET for v1. The session cookie is host-only on the
106
+ # single `<id>.proxy.propr.dev` host — correct because that host and
107
+ # app.propr.dev share the propr.dev registrable domain (same-site). Setting
108
+ # COOKIE_DOMAIN (e.g. `.proxy.propr.dev`) would scope the cookie across every
109
+ # instance's subdomain and is not supported for v1 proxy sessions.
110
+ # COOKIE_DOMAIN=
111
+
45
112
  # Logging Configuration
46
113
  LOG_LEVEL=info
47
114
  NODE_ENV=development
@@ -191,8 +258,21 @@ VIBE_TIMEOUT_MS=3600000
191
258
 
192
259
  # Dashboard API Configuration
193
260
  DASHBOARD_API_PORT=4000
194
- # Required in normal and demo mode for auth redirects.
195
- FRONTEND_URL=http://localhost:5173
261
+ # Browser origin: required in normal and demo mode for CORS and auth redirects.
262
+ # Defaults to http://localhost:5173 when unset. In hosted UI tunnel mode this is
263
+ # derived automatically as the hosted UI origin (https://app.propr.dev) — NOT the
264
+ # proxy host — so leave it COMMENTED to let derivation win. An uncommented value
265
+ # here always overrides the derived origin (set one only to force a custom
266
+ # origin). See the "Hosted UI tunnel" section above.
267
+ # FRONTEND_URL=http://localhost:5173
268
+ # Public URL the API is reached at (auth redirects, attachment links, cookie
269
+ # security). Defaults to http://localhost:4000 when unset; set it to the
270
+ # https://<id>.proxy.propr.dev host when the hosted UI tunnel is enabled.
271
+ # API_PUBLIC_URL=http://localhost:4000
272
+ # Session cookie domain. Leave UNSET for v1 — including hosted UI tunnel proxy
273
+ # sessions, which run on a single <id>.proxy.propr.dev host (see the tunnel
274
+ # section above). Only set it for a custom multi-subdomain deployment.
275
+ # COOKIE_DOMAIN=
196
276
  # Optional comma-separated redirect hosts for auth preview flows.
197
277
  # Entries are exact host matches by default. Prefix with "." or "*." only for
198
278
  # parent domains where every subdomain is trusted, for example .preview.example.com.
@@ -200,9 +280,16 @@ FRONTEND_URL=http://localhost:5173
200
280
  # AUTH_REDIRECT_ALLOWED_HOSTS=preview.example.com
201
281
 
202
282
  # GitHub OAuth Configuration
283
+ # The OAuth callback is served by the API and is derived automatically when left
284
+ # unset: <proxy host>/api/auth/github/callback in hosted UI tunnel mode, or
285
+ # http://localhost:4000/api/auth/github/callback for local development. Leave it
286
+ # commented so enabling the tunnel (token/instance id) cannot leave a stale
287
+ # localhost callback that breaks hosted OAuth — an active localhost value is used
288
+ # as-is even in tunnel mode (the launcher only warns). Uncomment to override; then
289
+ # register that exact URL in your GitHub OAuth App.
203
290
  GH_OAUTH_CLIENT_ID=your_github_oauth_client_id
204
291
  GH_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret
205
- GH_OAUTH_CALLBACK_URL=http://localhost:4000/api/auth/github/callback
292
+ # GH_OAUTH_CALLBACK_URL=http://localhost:4000/api/auth/github/callback
206
293
  SESSION_SECRET=your-session-secret-here
207
294
 
208
295
  # Bearer Token Authentication (CLI)
@@ -20,5 +20,6 @@ export { createImagesCommand } from "./imageCommands.js";
20
20
  export { createStartCommand } from "./startCommand.js";
21
21
  export { createStackStatusCommand, createStopCommand } from "./stackCommands.js";
22
22
  export { createUiCommand, createDocsCommand } from "./uiDocsCommands.js";
23
+ export { createTunnelCommand } from "./tunnelCommand.js";
23
24
  export { createTankCommand } from "./tankCommands.js";
24
25
  export { createRelayCommand } from "./relayCommands.js";
@@ -6,7 +6,7 @@
6
6
  import { Command } from "commander";
7
7
  import { createConfigManager } from "../config/index.js";
8
8
  import { getHostConfig } from "../orchestrator/index.js";
9
- import { renderStatusTable } from "../orchestrator/format.js";
9
+ import { renderStatusTable, renderTunnelSection } from "../orchestrator/format.js";
10
10
  import { printOutput } from "../utils/index.js";
11
11
  /** Creates the `status` command — local stack status. */
12
12
  export function createStackStatusCommand() {
@@ -30,10 +30,22 @@ Examples:
30
30
  process.exit(1);
31
31
  }
32
32
  const status = orch.getStackStatus(cfg);
33
- if (printOutput(status, options.json ?? false))
33
+ // The Cloudflare tunnel is a local managed service, so its health is part
34
+ // of local status. The reachability probe is best-effort with its own
35
+ // timeout and never throws, so it cannot fail the status command.
36
+ const tunnel = await orch.getTunnelStatus(cfg, status);
37
+ if (printOutput({ ...status, tunnel }, options.json ?? false))
34
38
  return;
35
39
  console.log("");
36
40
  console.log(renderStatusTable(status));
41
+ // The tunnel is an optional service most stacks never use. Only show the
42
+ // human-readable Tunnel section when it is configured or enabled, so the
43
+ // common case isn't cluttered with an all-"no" block. (The --json output
44
+ // above always includes the `tunnel` key for scripted consumers.)
45
+ if (tunnel.configured || tunnel.enabled) {
46
+ console.log("");
47
+ console.log(renderTunnelSection(tunnel));
48
+ }
37
49
  console.log("");
38
50
  if (!status.running) {
39
51
  console.log("Stack is not running. Start it with: propr start");