@porte/cli 0.1.1 → 0.1.2

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
@@ -1,25 +1,78 @@
1
- # @porte/cli
1
+ # Porte
2
2
 
3
- Run your local Grok sessions from your phone. This is the daemon that pairs a Mac with [useporte.dev](https://useporte.dev); Grok, your repos, and every transcript stay on the Mac.
3
+ Porte - means door in French - is a secure remote interface for your local Grok conversations.
4
+
5
+ Manage the same Grok threads and repos from your phone while they continue to run on your laptop. Porte does not replace the TUI, and each account can access only its own machines.
4
6
 
5
7
  ## Install
6
8
 
7
9
  ```sh
8
10
  npm i -g @porte/cli
11
+ porte pair
12
+ ```
13
+
14
+ Or hand it to your agent: `Fetch and execute the instructions from https://useporte.dev/agent-setup/prompt.md to set up Porte on this machine.`
15
+
16
+ ## How it works
17
+
18
+ 1. Run the daemon on the machine where you already use Grok.
19
+ 2. Sign in on your phone and pair that machine.
20
+ 3. Open a conversation — or start a new one in a known repo.
21
+ 4. Read the transcript. Prompt. Approve or deny.
22
+
23
+ ```
24
+ Phone (your account) → Porte → your paired machine
25
+
26
+ Grok agent
27
+
28
+ local conversations + repos
29
+ ```
30
+
31
+ ## What Porte handles
32
+
33
+ Porte relays remote actions while your machine keeps the Grok runtime and all local data.
34
+
35
+ | ☁️ Us | 💻 Your machine |
36
+ | -------------------------------------- | ------------------------- |
37
+ | App account + pairing | `grok.com` login, spend |
38
+ | Conversation titles (id, cwd, updated) | Repos, files, transcripts |
39
+ | Live relay of prompts and approvals | The Grok process |
40
+
41
+ ## Safety
42
+
43
+ Remote Grok is the same Grok you already run.
44
+
45
+ - Starts in **that project’s directory**
46
+ - Inherits your `AGENTS.md`, rules, hooks, sandbox, and ask/deny
47
+ - No `--always-approve`. No extra filesystem or network power
48
+ - A click on the TUI is still a click on the phone. Deny still denies
49
+
50
+ ## Development
51
+
52
+ ```sh
53
+ pnpm install
54
+ pnpm dev # web on :3000; `pnpm dev up` connects a local host through the tunnel
55
+ pnpm turbo run lint typecheck test:unit test:integration
56
+ pnpm --filter @porte/web test:design # Playwright pictures; Mac only, run before a commit
9
57
  ```
10
58
 
11
- Needs Node 22 or newer, and the `grok` CLI on the path and signed in.
59
+ Cloudflare types are generated (`worker-configuration.d.ts`, gitignored). Turbo runs `cf-typegen` before lint, typecheck, tests, and build, so a fresh checkout sees what a dev does.
60
+
61
+ ### Releasing the CLI
12
62
 
13
- ## Use
63
+ `apps/host` publishes as `@porte/cli`. A release is a version bump on `main`:
14
64
 
15
65
  ```sh
16
- porte pair # link this Mac to your account: copy the code, approve it in the browser
17
- porte up # connect, so the phone can reach it
18
- porte unpair # end the pairing
66
+ pnpm --filter @porte/cli version patch --no-git-checks # bumps apps/host/package.json only
67
+ git commit -am "release(cli): x.y.z" && git push
19
68
  ```
20
69
 
21
- ## What it does not do
70
+ `.github/workflows/publish-cli.yaml` lints, typechecks, tests, builds, and publishes with provenance through npm trusted publishing (`pnpm publish --provenance`, no token). A push that leaves the version alone publishes nothing. The npm page shows this README, copied at pack time.
71
+
72
+ ### Deploying the web app
73
+
74
+ Cloudflare Workers Builds is connected to this repository: every push to `main` builds and deploys the web app. Nothing is deployed by hand.
22
75
 
23
- Porte adds no permissions. Remote Grok starts in the project's directory and inherits your `AGENTS.md`, hooks, sandbox, and ask/deny rules. Deny on the phone is deny on the Mac.
76
+ ## License
24
77
 
25
- Source and issues: [github.com/alexander-zuev/porte](https://github.com/alexander-zuev/porte). Apache-2.0.
78
+ [Apache License 2.0](LICENSE).
@@ -5640,11 +5640,11 @@ var ConfigurationNotFoundError = class extends h(CONFIGURATION_NOT_FOUND_ERROR)
5640
5640
  const HOST_OFFLINE_ERROR = "HostOfflineError";
5641
5641
  const HOST_ALREADY_PAIRED_ERROR = "HostAlreadyPairedError";
5642
5642
  const WORKSPACE_NOT_ALLOWED_ERROR = "WorkspaceNotAllowedError";
5643
- /** The path is not one the Mac reported, so the daemon will not open it. */
5643
+ /** The path is not one the machine reported, so the daemon will not open it. */
5644
5644
  var WorkspaceNotAllowedError = class extends h(WORKSPACE_NOT_ALLOWED_ERROR) {
5645
5645
  constructor() {
5646
5646
  super({
5647
- message: "That repository is not available on this Mac",
5647
+ message: "That repository is not available on this machine",
5648
5648
  classification: "terminal"
5649
5649
  });
5650
5650
  }
@@ -5778,17 +5778,17 @@ const HostPlatformSchema = _enum([
5778
5778
  //#endregion
5779
5779
  //#region ../../packages/core/src/host/account-host.ts
5780
5780
  /**
5781
- * Which Mac an account owns, if any.
5781
+ * Which machine an account owns, if any.
5782
5782
  *
5783
- * Durable facts only. Nothing here says whether the Mac can be reached or what
5783
+ * Durable facts only. Nothing here says whether the machine can be reached or what
5784
5784
  * is on it, because the database cannot see either; the relay answers both.
5785
5785
  * Loading and error are absent for the same reason: they describe a request,
5786
5786
  * not the account.
5787
5787
  */
5788
5788
  /**
5789
- * A paired Mac, as the database knows it.
5789
+ * A paired machine, as the database knows it.
5790
5790
  *
5791
- * There is no availability here. Whether a Mac is reachable is a live question
5791
+ * There is no availability here. Whether a machine is reachable is a live question
5792
5792
  * the relay answers, and a read that guessed at it would be a second version of
5793
5793
  * a fact it cannot see. `lastSeenAt` is null until a daemon has announced
5794
5794
  * itself, because approving a grant is not an observation of one.
@@ -5833,7 +5833,7 @@ const ProblemDetailsSchema = looseObject({
5833
5833
  title: string(),
5834
5834
  /**
5835
5835
  * Safe human-readable explanation for this occurrence; clients must not parse it.
5836
- * @example "Porte is not connected on the paired Mac."
5836
+ * @example "Porte is not connected on the paired machine."
5837
5837
  */
5838
5838
  detail: string().optional(),
5839
5839
  /**
@@ -6223,7 +6223,7 @@ function formatPairingCode(code) {
6223
6223
  /**
6224
6224
  * Where the code was asked for, judged against where it is being answered.
6225
6225
  *
6226
- * The server compares, not the screen. Both halves normally happen on one Mac,
6226
+ * The server compares, not the screen. Both halves normally happen on one machine,
6227
6227
  * so `elsewhere` is the whole signal: someone else's machine asked for a code
6228
6228
  * you are about to approve.
6229
6229
  */
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { k as setLogSink } from "./client-CpzDWkFF.js";
2
+ import { k as setLogSink } from "./client-Cvulvd-1.js";
3
3
  //#region src/main.ts
4
4
  const major = Number(process.versions.node.split(".")[0]);
5
5
  if (Number.isNaN(major) || major < 22) {
@@ -11,7 +11,7 @@ setLogSink((_level, line) => {
11
11
  });
12
12
  const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
13
13
  process.env.LOG_LEVEL ??= verbose ? "DEBUG" : "WARN";
14
- const { run } = await import("./run-cli-Djt_v7Px.js");
14
+ const { run } = await import("./run-cli-CoetNCwK.js");
15
15
  const code = await run(process.argv.slice(2), {
16
16
  stdout: process.stdout,
17
17
  stderr: process.stderr,
@@ -1,4 +1,4 @@
1
- import { $ as INTERNAL_SERVER_ERROR, A as ProblemDetailsSchema, B as PermissionNotFoundError, C as DeviceTokenErrorSchema, D as PORTE_CLI_CLIENT_ID, E as PAIRING_CODE_PATH, F as AgentUnresponsiveError, G as makeConversationSummary, H as ConversationEventSchema, I as ConfigurationNotFoundError, J as IsoDateTimeSchema, K as ConversationIdSchema, L as ConversationBusyError, M as isClassifiedError, N as isDomainError, O as createLogger, P as WorkspaceNotAllowedError, Q as turnIdFor, R as ConversationNotFoundError, S as DeviceCodeResponseSchema, T as DeviceTokenResponseSchema, U as ToolViewSchema, V as TurnNotFoundError, W as ConversationCursorSchema, X as PermissionIdSchema, Y as MessageIdSchema, Z as ToolCallIdSchema, _ as readJsonRpcIncoming, _t as url, a as HOST_APPLICATION_ERROR_CODE, at as _enum, b as DEVICE_CODE_GRANT_TYPE, c as HOST_CONVERSATION_SUBPROTOCOL, ct as email, d as JSON_RPC_ERROR_CODES, dt as literal, et as InternalServerError, f as JsonRpcReadError, ft as number, g as jsonRpcNotification, gt as unknown, h as jsonRpcError, ht as string, i as HostControlMethods, it as h, j as HostPlatformSchema, l as HostRequestIdSchema, lt as httpUrl, m as handleJsonRpcRequest, mt as record, n as sendJsonRpcFrame, nt as CODING_AGENT_UNAVAILABLE_ERROR, o as HOST_APPLICATION_ERROR_MESSAGE, ot as array, p as JsonRpcTextSchema, pt as object, q as ElicitationIdSchema, r as HostConversationMethods, rt as CodingAgentUnavailableError, s as HOST_CONTROL_SUBPROTOCOL, st as discriminatedUnion, t as JsonRpcSendError, tt as ServiceUnavailableError, u as SequenceNumberSchema, ut as json, v as readJsonRpcTextFrame, w as DeviceTokenRequestSchema, x as DeviceCodeRequestSchema, y as formatPairingCode, z as ElicitationNotFoundError } from "./client-CpzDWkFF.js";
1
+ import { $ as INTERNAL_SERVER_ERROR, A as ProblemDetailsSchema, B as PermissionNotFoundError, C as DeviceTokenErrorSchema, D as PORTE_CLI_CLIENT_ID, E as PAIRING_CODE_PATH, F as AgentUnresponsiveError, G as makeConversationSummary, H as ConversationEventSchema, I as ConfigurationNotFoundError, J as IsoDateTimeSchema, K as ConversationIdSchema, L as ConversationBusyError, M as isClassifiedError, N as isDomainError, O as createLogger, P as WorkspaceNotAllowedError, Q as turnIdFor, R as ConversationNotFoundError, S as DeviceCodeResponseSchema, T as DeviceTokenResponseSchema, U as ToolViewSchema, V as TurnNotFoundError, W as ConversationCursorSchema, X as PermissionIdSchema, Y as MessageIdSchema, Z as ToolCallIdSchema, _ as readJsonRpcIncoming, _t as url, a as HOST_APPLICATION_ERROR_CODE, at as _enum, b as DEVICE_CODE_GRANT_TYPE, c as HOST_CONVERSATION_SUBPROTOCOL, ct as email, d as JSON_RPC_ERROR_CODES, dt as literal, et as InternalServerError, f as JsonRpcReadError, ft as number, g as jsonRpcNotification, gt as unknown, h as jsonRpcError, ht as string, i as HostControlMethods, it as h, j as HostPlatformSchema, l as HostRequestIdSchema, lt as httpUrl, m as handleJsonRpcRequest, mt as record, n as sendJsonRpcFrame, nt as CODING_AGENT_UNAVAILABLE_ERROR, o as HOST_APPLICATION_ERROR_MESSAGE, ot as array, p as JsonRpcTextSchema, pt as object, q as ElicitationIdSchema, r as HostConversationMethods, rt as CodingAgentUnavailableError, s as HOST_CONTROL_SUBPROTOCOL, st as discriminatedUnion, t as JsonRpcSendError, tt as ServiceUnavailableError, u as SequenceNumberSchema, ut as json, v as readJsonRpcTextFrame, w as DeviceTokenRequestSchema, x as DeviceCodeRequestSchema, y as formatPairingCode, z as ElicitationNotFoundError } from "./client-Cvulvd-1.js";
2
2
  import { homedir, hostname } from "node:os";
3
3
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { execFileSync, spawn } from "node:child_process";
@@ -98,7 +98,7 @@ var UnsupportedPlatformError = class extends h("UnsupportedPlatformError") {
98
98
  }
99
99
  };
100
100
  /**
101
- * What this Mac calls itself.
101
+ * What this machine calls itself.
102
102
  *
103
103
  * `platform` stays the runtime's own token, so what is stored is what Node
104
104
  * reported. Turning `darwin` into `macOS` is the reader's job, and spelling it
@@ -168,7 +168,7 @@ var WebSocketHandlerError = class extends h("WebSocketHandlerError") {
168
168
  //#endregion
169
169
  //#region src/entrypoints/cli/version.ts
170
170
  /** Package version. Source is `package.json`. */
171
- const VERSION = "0.1.1";
171
+ const VERSION = "0.1.2";
172
172
  //#endregion
173
173
  //#region src/entrypoints/cli/cli-error.ts
174
174
  /** Bad arguments or missing required flags. */
@@ -199,7 +199,7 @@ function formatError(error) {
199
199
  if (error instanceof ConfigError || error instanceof UnsupportedPlatformError) body = `Error (ECONFIG): Porte configuration is invalid.\n${error.message}`;
200
200
  else if (error instanceof HostNotPairedError) body = error.message;
201
201
  else if (error instanceof WebSocketHandlerError || error instanceof JsonRpcSendError) body = "Error (ERELAY): host connection stopped. Restart `porte up`.";
202
- else if (error instanceof WebSocketHandshakeRefused) body = error.status === 401 || error.status === 403 ? `Error (EAUTH): ${error.message} Run \`porte pair\` to pair this Mac again.` : `Error (ERELAY): ${error.message}`;
202
+ else if (error instanceof WebSocketHandshakeRefused) body = error.status === 401 || error.status === 403 ? `Error (EAUTH): ${error.message} Run \`porte pair\` to pair this machine again.` : `Error (ERELAY): ${error.message}`;
203
203
  else if (error instanceof WebSocketProtocolClose) body = `Error (ERELAY): ${error.message}`;
204
204
  else if (error instanceof PairingError) body = `Error (EPAIR): ${error.message} Run \`porte pair\` to try again.`;
205
205
  else body = `Error (ECRED): ${error.message}`;
@@ -340,7 +340,7 @@ function reportUnexpectedCliError(stderr, cause) {
340
340
  //#endregion
341
341
  //#region src/application/commands/pair-host.ts
342
342
  /**
343
- * Pair this Mac with a Porte account.
343
+ * Pair this machine with a Porte account.
344
344
  *
345
345
  * The daemon asks for a code, shows it, and waits. Approval happens on the
346
346
  * person's phone, so this machine never handles a password and the credential
@@ -708,7 +708,7 @@ async function runPairCommand(input) {
708
708
  onPrompt: (prompt) => {
709
709
  const shown = formatPairingCode(prompt.userCode);
710
710
  const waiting = `Waiting for approval — the code expires in ${String(Math.round(prompt.expiresInSeconds / 60))} minutes. ${WAITING_EMOJI}`;
711
- output.title("Pair this Mac with Porte", PAIR_EMOJI);
711
+ output.title("Pair this machine with Porte", PAIR_EMOJI);
712
712
  if (!interactive) {
713
713
  output.raw(`First copy your pairing code: ${code(shown)}`);
714
714
  output.raw(`Then open ${url(prompt.verificationUri)} in your browser.`);
@@ -754,7 +754,7 @@ async function runPairCommand(input) {
754
754
  const machine = strong(describeThisMachine().name);
755
755
  output.done(account === null ? `Paired ${machine} with Porte` : `Paired ${machine} with ${strong(account)} on Porte`);
756
756
  output.blank();
757
- output.raw(` Run ${code("porte up")} to control this Mac's Grok conversations from anywhere`);
757
+ output.raw(` Run ${code("porte up")} to control this machine's Grok conversations from anywhere`);
758
758
  output.note("Expires in 7 days if it never connects");
759
759
  return 0;
760
760
  }
@@ -772,8 +772,8 @@ Options:
772
772
  -v, --verbose Write debug logs to stderr
773
773
 
774
774
  Commands:
775
- pair Link this Mac to your Porte account
776
- unpair End this Mac's pairing
775
+ pair Link this machine to your Porte account
776
+ unpair End this machine's pairing
777
777
  up Connect this host to Porte
778
778
 
779
779
  Examples:
@@ -784,7 +784,7 @@ Examples:
784
784
  const PAIR_HELP = `Usage:
785
785
  porte pair
786
786
 
787
- Link this Mac to your Porte account. Prints a code to approve in any browser,
787
+ Link this machine to your Porte account. Prints a code to approve in any browser,
788
788
  then waits. Run this once; \`porte up\` uses what it stores.
789
789
 
790
790
  Options:
@@ -798,7 +798,7 @@ Environment:
798
798
  const UNPAIR_HELP = `Usage:
799
799
  porte unpair
800
800
 
801
- End this Mac's pairing. Porte stops accepting it, and the local credential is
801
+ End this machine's pairing. Porte stops accepting it, and the local credential is
802
802
  deleted. Run \`porte pair\` to connect it again.
803
803
 
804
804
  Options:
@@ -4149,12 +4149,12 @@ async function runUnpairCommand(input) {
4149
4149
  const output = createOutput(input.stderr);
4150
4150
  const stored = await resources.credentials.read();
4151
4151
  if (stored === null) {
4152
- output.done("This Mac is not paired.");
4152
+ output.done("This machine is not paired.");
4153
4153
  return 0;
4154
4154
  }
4155
4155
  await resources.authorizer.revoke(stored.token);
4156
4156
  await resources.credentials.clear();
4157
- output.done(`Unpaired this Mac from ${output.emphasis.strong(new URL(stored.baseUrl).host)}`);
4157
+ output.done(`Unpaired this machine from ${output.emphasis.strong(new URL(stored.baseUrl).host)}`);
4158
4158
  return 0;
4159
4159
  }
4160
4160
  //#endregion
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "name": "@porte/cli",
4
- "version": "0.1.1",
5
- "description": "Run your local Grok sessions from your phone. The daemon that pairs a Mac with useporte.dev.",
4
+ "version": "0.1.2",
5
+ "description": "Run your local Grok sessions from your phone. The daemon that pairs a machine with useporte.dev.",
6
6
  "keywords": [
7
7
  "acp",
8
8
  "agent",