remodex-cli 1.0.0

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.
Files changed (99) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +105 -0
  3. package/dist/archive-store.d.ts +28 -0
  4. package/dist/archive-store.js +68 -0
  5. package/dist/archive-store.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +88 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/codex-process.d.ts +186 -0
  10. package/dist/codex-process.js +2111 -0
  11. package/dist/codex-process.js.map +1 -0
  12. package/dist/debug-trace-store.d.ts +15 -0
  13. package/dist/debug-trace-store.js +78 -0
  14. package/dist/debug-trace-store.js.map +1 -0
  15. package/dist/doctor.d.ts +58 -0
  16. package/dist/doctor.js +670 -0
  17. package/dist/doctor.js.map +1 -0
  18. package/dist/firebase-auth.d.ts +35 -0
  19. package/dist/firebase-auth.js +132 -0
  20. package/dist/firebase-auth.js.map +1 -0
  21. package/dist/gallery-store.d.ts +67 -0
  22. package/dist/gallery-store.js +333 -0
  23. package/dist/gallery-store.js.map +1 -0
  24. package/dist/git-assist.d.ts +7 -0
  25. package/dist/git-assist.js +51 -0
  26. package/dist/git-assist.js.map +1 -0
  27. package/dist/git-operations.d.ts +63 -0
  28. package/dist/git-operations.js +292 -0
  29. package/dist/git-operations.js.map +1 -0
  30. package/dist/image-store.d.ts +23 -0
  31. package/dist/image-store.js +142 -0
  32. package/dist/image-store.js.map +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +198 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/mdns.d.ts +7 -0
  37. package/dist/mdns.js +49 -0
  38. package/dist/mdns.js.map +1 -0
  39. package/dist/parser.d.ts +620 -0
  40. package/dist/parser.js +423 -0
  41. package/dist/parser.js.map +1 -0
  42. package/dist/path-utils.d.ts +4 -0
  43. package/dist/path-utils.js +34 -0
  44. package/dist/path-utils.js.map +1 -0
  45. package/dist/project-history.d.ts +10 -0
  46. package/dist/project-history.js +73 -0
  47. package/dist/project-history.js.map +1 -0
  48. package/dist/prompt-history-backup.d.ts +15 -0
  49. package/dist/prompt-history-backup.js +46 -0
  50. package/dist/prompt-history-backup.js.map +1 -0
  51. package/dist/proxy.d.ts +15 -0
  52. package/dist/proxy.js +95 -0
  53. package/dist/proxy.js.map +1 -0
  54. package/dist/push-i18n.d.ts +7 -0
  55. package/dist/push-i18n.js +75 -0
  56. package/dist/push-i18n.js.map +1 -0
  57. package/dist/push-relay.d.ts +29 -0
  58. package/dist/push-relay.js +70 -0
  59. package/dist/push-relay.js.map +1 -0
  60. package/dist/recording-store.d.ts +51 -0
  61. package/dist/recording-store.js +158 -0
  62. package/dist/recording-store.js.map +1 -0
  63. package/dist/screenshot.d.ts +28 -0
  64. package/dist/screenshot.js +98 -0
  65. package/dist/screenshot.js.map +1 -0
  66. package/dist/sdk-process.d.ts +180 -0
  67. package/dist/sdk-process.js +960 -0
  68. package/dist/sdk-process.js.map +1 -0
  69. package/dist/session.d.ts +144 -0
  70. package/dist/session.js +687 -0
  71. package/dist/session.js.map +1 -0
  72. package/dist/sessions-index.d.ts +130 -0
  73. package/dist/sessions-index.js +1817 -0
  74. package/dist/sessions-index.js.map +1 -0
  75. package/dist/setup-launchd.d.ts +9 -0
  76. package/dist/setup-launchd.js +115 -0
  77. package/dist/setup-launchd.js.map +1 -0
  78. package/dist/setup-systemd.d.ts +9 -0
  79. package/dist/setup-systemd.js +122 -0
  80. package/dist/setup-systemd.js.map +1 -0
  81. package/dist/startup-info.d.ts +9 -0
  82. package/dist/startup-info.js +116 -0
  83. package/dist/startup-info.js.map +1 -0
  84. package/dist/usage.d.ts +69 -0
  85. package/dist/usage.js +545 -0
  86. package/dist/usage.js.map +1 -0
  87. package/dist/version.d.ts +13 -0
  88. package/dist/version.js +43 -0
  89. package/dist/version.js.map +1 -0
  90. package/dist/websocket.d.ts +132 -0
  91. package/dist/websocket.js +3551 -0
  92. package/dist/websocket.js.map +1 -0
  93. package/dist/worktree-store.d.ts +26 -0
  94. package/dist/worktree-store.js +61 -0
  95. package/dist/worktree-store.js.map +1 -0
  96. package/dist/worktree.d.ts +47 -0
  97. package/dist/worktree.js +330 -0
  98. package/dist/worktree.js.map +1 -0
  99. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ This package is part of the Remodex project.
2
+
3
+ License: SEE LICENSE IN LICENSE
4
+
5
+ The governing license for this package is the repository root LICENSE, including
6
+ the Bridge Redistribution Exception that applies to the Bridge Server component.
7
+
8
+ Repository:
9
+ https://github.com/K9i-0/ccpocket
10
+
11
+ Root license:
12
+ https://github.com/K9i-0/ccpocket/blob/main/LICENSE
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # remodex-cli
2
+
3
+ Bridge server that connects [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) and [Codex CLI](https://github.com/openai/codex) to mobile devices via WebSocket.
4
+
5
+ This is the server component of [remodex](https://github.com/K9i-0/ccpocket) — a mobile client for Claude Code and Codex.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx remodex-cli@latest
11
+ ```
12
+
13
+ A QR code will appear in your terminal. Scan it with the remodex mobile app to connect.
14
+
15
+ > Warning
16
+ > Versions older than `1.25.0` are deprecated and should not be used for new installs due to potential Anthropic policy concerns around OAuth-based usage.
17
+ > Upgrade to `>=1.25.0` and use `ANTHROPIC_API_KEY` instead of OAuth.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # Run directly (no install needed)
23
+ npx remodex-cli@latest
24
+
25
+ # Or install globally
26
+ npm install -g remodex-cli
27
+ remodex-cli
28
+ ```
29
+
30
+ ## Configuration
31
+
32
+ | Environment Variable | Default | Description |
33
+ |---------------------|---------|-------------|
34
+ | `BRIDGE_PORT` | `8765` | WebSocket port |
35
+ | `BRIDGE_HOST` | `0.0.0.0` | Bind address |
36
+ | `BRIDGE_API_KEY` | (none) | API key authentication (enabled when set) |
37
+ | `BRIDGE_PUBLIC_WS_URL` | (none) | Public `ws://` / `wss://` URL used for startup deep link and QR code |
38
+ | `BRIDGE_DEMO_MODE` | (none) | Demo mode: hide Tailscale IPs and API key from QR code / logs |
39
+ | `BRIDGE_RECORDING` | (none) | Enable session recording for debugging (enabled when set) |
40
+ | `BRIDGE_DISABLE_MDNS` | (none) | Disable mDNS auto-discovery advertisement (enabled when set) |
41
+ | `HTTPS_PROXY` | (none) | Proxy for outgoing fetch requests (`http://`, `socks5://`) |
42
+
43
+ ```bash
44
+ # Example: custom port with API key
45
+ BRIDGE_PORT=9000 BRIDGE_API_KEY=my-secret npx remodex-cli@latest
46
+
47
+ # Example: expose Bridge through a reverse proxy / ngrok
48
+ BRIDGE_PUBLIC_WS_URL=wss://example.ngrok-free.app npx remodex-cli@latest
49
+
50
+ # Example: same setting via CLI flag
51
+ remodex-cli --public-ws-url wss://example.ngrok-free.app
52
+
53
+ # Example: disable mDNS advertisement
54
+ BRIDGE_DISABLE_MDNS=1 npx remodex-cli@latest
55
+ # or via CLI flag
56
+ remodex-cli --no-mdns
57
+ ```
58
+
59
+ When `BRIDGE_PUBLIC_WS_URL` is set, the startup deep link and terminal QR code
60
+ use that public URL instead of the LAN address. This is useful when the Bridge
61
+ is reachable through a reverse proxy, tunnel, or public domain.
62
+
63
+ Without it, the printed QR code is LAN-oriented by default and typically encodes
64
+ something like `ws://192.168.x.x:8765`.
65
+
66
+ ## Requirements
67
+
68
+ - Node.js v18+
69
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) and/or [Codex CLI](https://github.com/openai/codex)
70
+
71
+ ## Health Check
72
+
73
+ Run the built-in doctor command to verify your environment:
74
+
75
+ ```bash
76
+ npx remodex-cli@latest doctor
77
+ ```
78
+
79
+ It checks Node.js, Git, CLI providers, macOS permissions (Screen Recording, Keychain), network connectivity, and more.
80
+
81
+ ## Architecture
82
+
83
+ ```
84
+ Mobile App ←WebSocket→ Bridge Server ←stdio→ Claude Code CLI
85
+ ```
86
+
87
+ The bridge server spawns and manages Claude Code CLI processes, translating WebSocket messages to/from the CLI's stdio interface. It supports multiple concurrent sessions.
88
+
89
+ ## License
90
+
91
+ This package is governed by the [Remodex license](../../LICENSE).
92
+
93
+ The repository remains under FSL-1.1-MIT, with a specific Bridge Redistribution
94
+ Exception that allows unofficial redistribution of the Bridge Server, including
95
+ environment-specific builds and forks for Windows, WSL, proxy-restricted, or
96
+ other hard-to-validate environments.
97
+
98
+ If you redistribute this package or a modified fork:
99
+
100
+ - do not imply it is official, endorsed, or supported by the Remodex maintainer
101
+ - preserve the license text and clearly state that the software is provided "AS IS"
102
+ - make clear that compliance with Anthropic, OpenAI, network, enterprise, and other third-party terms is the responsibility of the redistributor and end user
103
+
104
+ In short: unofficial Bridge redistributions are permitted for compatibility and
105
+ support purposes, but they remain unsupported and at your own risk.
@@ -0,0 +1,28 @@
1
+ export interface ArchivedSession {
2
+ sessionId: string;
3
+ provider: "claude" | "codex";
4
+ projectPath: string;
5
+ archivedAt: string;
6
+ }
7
+ /**
8
+ * Manages a persistent set of archived session IDs.
9
+ * Data is stored in `~/.remodex/archived-sessions.json`.
10
+ */
11
+ export declare class ArchiveStore {
12
+ private readonly dirPath;
13
+ private readonly filePath;
14
+ /** In-memory cache of archived session IDs for O(1) lookup. */
15
+ private cache;
16
+ private data;
17
+ constructor();
18
+ /** Initialise the store: create directory if needed and load existing data. */
19
+ init(): Promise<void>;
20
+ /** Archive a session. Idempotent – archiving an already-archived session is a no-op. */
21
+ archive(sessionId: string, provider: "claude" | "codex", projectPath: string): Promise<void>;
22
+ /** Check whether a session is archived. */
23
+ isArchived(sessionId: string): boolean;
24
+ /** Return the full set of archived session IDs (for bulk filtering). */
25
+ archivedIds(): ReadonlySet<string>;
26
+ /** Atomic write: write to temp file, then rename. */
27
+ private save;
28
+ }
@@ -0,0 +1,68 @@
1
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { randomUUID } from "node:crypto";
5
+ /**
6
+ * Manages a persistent set of archived session IDs.
7
+ * Data is stored in `~/.remodex/archived-sessions.json`.
8
+ */
9
+ export class ArchiveStore {
10
+ dirPath;
11
+ filePath;
12
+ /** In-memory cache of archived session IDs for O(1) lookup. */
13
+ cache = new Set();
14
+ data = { version: 1, archivedSessions: [] };
15
+ constructor() {
16
+ this.dirPath = join(homedir(), ".remodex");
17
+ this.filePath = join(this.dirPath, "archived-sessions.json");
18
+ }
19
+ /** Initialise the store: create directory if needed and load existing data. */
20
+ async init() {
21
+ await mkdir(this.dirPath, { recursive: true });
22
+ try {
23
+ const raw = await readFile(this.filePath, "utf-8");
24
+ const parsed = JSON.parse(raw);
25
+ if (parsed.version === 1 && Array.isArray(parsed.archivedSessions)) {
26
+ this.data = parsed;
27
+ this.cache = new Set(parsed.archivedSessions.map((s) => s.sessionId));
28
+ }
29
+ }
30
+ catch {
31
+ // File doesn't exist or is corrupted – start fresh.
32
+ this.data = { version: 1, archivedSessions: [] };
33
+ this.cache = new Set();
34
+ }
35
+ console.log(`[archive-store] Loaded ${this.cache.size} archived session(s)`);
36
+ }
37
+ /** Archive a session. Idempotent – archiving an already-archived session is a no-op. */
38
+ async archive(sessionId, provider, projectPath) {
39
+ if (this.cache.has(sessionId))
40
+ return;
41
+ const entry = {
42
+ sessionId,
43
+ provider,
44
+ projectPath,
45
+ archivedAt: new Date().toISOString(),
46
+ };
47
+ this.data.archivedSessions.push(entry);
48
+ this.cache.add(sessionId);
49
+ await this.save();
50
+ console.log(`[archive-store] Archived session ${sessionId}`);
51
+ }
52
+ /** Check whether a session is archived. */
53
+ isArchived(sessionId) {
54
+ return this.cache.has(sessionId);
55
+ }
56
+ /** Return the full set of archived session IDs (for bulk filtering). */
57
+ archivedIds() {
58
+ return this.cache;
59
+ }
60
+ // ---- internal ----
61
+ /** Atomic write: write to temp file, then rename. */
62
+ async save() {
63
+ const tmp = join(this.dirPath, `archived-sessions.${randomUUID()}.tmp`);
64
+ await writeFile(tmp, JSON.stringify(this.data, null, 2), "utf-8");
65
+ await rename(tmp, this.filePath);
66
+ }
67
+ }
68
+ //# sourceMappingURL=archive-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-store.js","sourceRoot":"","sources":["../src/archive-store.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ import { setupProxy } from "./proxy.js";
3
+ import { platform } from "node:os";
4
+ import { startServer } from "./index.js";
5
+ // Configure global fetch proxy before any network calls
6
+ setupProxy();
7
+ const args = process.argv.slice(2);
8
+ // Check for subcommand
9
+ const subcommand = args.find((a) => !a.startsWith("-"));
10
+ function parseFlag(name) {
11
+ const idx = args.indexOf(`--${name}`);
12
+ if (idx === -1 || idx + 1 >= args.length)
13
+ return undefined;
14
+ return args[idx + 1];
15
+ }
16
+ function hasFlag(name) {
17
+ return args.includes(`--${name}`);
18
+ }
19
+ if (subcommand === "doctor") {
20
+ // Doctor subcommand: check environment health
21
+ const jsonOutput = hasFlag("json");
22
+ import("./doctor.js")
23
+ .then(({ runDoctor, printReport }) => runDoctor().then((report) => {
24
+ if (jsonOutput) {
25
+ console.log(JSON.stringify(report));
26
+ }
27
+ else {
28
+ printReport(report);
29
+ }
30
+ process.exit(report.allRequiredPassed ? 0 : 1);
31
+ }))
32
+ .catch((err) => {
33
+ console.error("Doctor failed:", err);
34
+ process.exit(1);
35
+ });
36
+ }
37
+ else if (subcommand === "setup") {
38
+ // Service setup subcommand (platform-specific)
39
+ const opts = {
40
+ port: parseFlag("port"),
41
+ host: parseFlag("host"),
42
+ apiKey: parseFlag("api-key"),
43
+ publicWsUrl: parseFlag("public-ws-url"),
44
+ };
45
+ if (platform() === "darwin") {
46
+ import("./setup-launchd.js")
47
+ .then(({ setupLaunchd, uninstallLaunchd }) => {
48
+ hasFlag("uninstall") ? uninstallLaunchd() : setupLaunchd(opts);
49
+ })
50
+ .catch((err) => {
51
+ console.error("Setup failed:", err);
52
+ process.exit(1);
53
+ });
54
+ }
55
+ else if (platform() === "linux") {
56
+ import("./setup-systemd.js")
57
+ .then(({ setupSystemd, uninstallSystemd }) => {
58
+ hasFlag("uninstall") ? uninstallSystemd() : setupSystemd(opts);
59
+ })
60
+ .catch((err) => {
61
+ console.error("Setup failed:", err);
62
+ process.exit(1);
63
+ });
64
+ }
65
+ else {
66
+ console.error(`ERROR: 'setup' is not supported on ${platform()}. Supported: macOS (launchd), Linux (systemd).`);
67
+ process.exit(1);
68
+ }
69
+ }
70
+ else {
71
+ // Server mode: set env vars from CLI flags, then start
72
+ const port = parseFlag("port");
73
+ const host = parseFlag("host");
74
+ const apiKey = parseFlag("api-key");
75
+ const publicWsUrl = parseFlag("public-ws-url");
76
+ if (port)
77
+ process.env.BRIDGE_PORT = port;
78
+ if (host)
79
+ process.env.BRIDGE_HOST = host;
80
+ if (apiKey)
81
+ process.env.BRIDGE_API_KEY = apiKey;
82
+ if (publicWsUrl)
83
+ process.env.BRIDGE_PUBLIC_WS_URL = publicWsUrl;
84
+ if (hasFlag("no-mdns"))
85
+ process.env.BRIDGE_DISABLE_MDNS = "1";
86
+ startServer();
87
+ }
88
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { ServerMessage, ProcessStatus } from "./parser.js";
3
+ export interface CodexStartOptions {
4
+ threadId?: string;
5
+ approvalPolicy?: "never" | "on-request" | "on-failure" | "untrusted";
6
+ sandboxMode?: "read-only" | "workspace-write" | "danger-full-access";
7
+ model?: string;
8
+ modelReasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh";
9
+ networkAccessEnabled?: boolean;
10
+ webSearchMode?: "disabled" | "cached" | "live";
11
+ collaborationMode?: "plan" | "default";
12
+ }
13
+ export interface CodexProcessEvents {
14
+ message: [ServerMessage];
15
+ status: [ProcessStatus];
16
+ exit: [number | null];
17
+ }
18
+ /** Skill metadata returned by the Codex `skills/list` RPC. */
19
+ export interface CodexSkillMetadata {
20
+ name: string;
21
+ path: string;
22
+ description: string;
23
+ shortDescription?: string;
24
+ enabled: boolean;
25
+ scope: string;
26
+ displayName?: string;
27
+ defaultPrompt?: string;
28
+ brandColor?: string;
29
+ }
30
+ export interface CodexThreadSummary {
31
+ id: string;
32
+ preview: string;
33
+ createdAt: number;
34
+ updatedAt: number;
35
+ cwd: string;
36
+ agentNickname: string | null;
37
+ agentRole: string | null;
38
+ gitBranch: string | null;
39
+ name: string | null;
40
+ }
41
+ export declare function buildCodexSpawnSpec(projectPath: string, platform?: NodeJS.Platform): {
42
+ command: string;
43
+ args: string[];
44
+ options: {
45
+ cwd: string;
46
+ stdio: "pipe";
47
+ env: NodeJS.ProcessEnv;
48
+ windowsVerbatimArguments?: boolean;
49
+ };
50
+ };
51
+ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
52
+ private child;
53
+ private _status;
54
+ private _threadId;
55
+ private _agentNickname;
56
+ private _agentRole;
57
+ private stopped;
58
+ private startModel;
59
+ private inputResolve;
60
+ private pendingTurnId;
61
+ private pendingTurnCompletion;
62
+ private pendingApprovals;
63
+ private pendingUserInputs;
64
+ private lastTokenUsage;
65
+ /** Full skill metadata from the last `skills/list` response. */
66
+ private _skills;
67
+ /** Project path stored for re-fetching skills on `skills/changed`. */
68
+ private _projectPath;
69
+ /** Expose skill metadata so session/websocket can access it. */
70
+ get skills(): CodexSkillMetadata[];
71
+ private rpcSeq;
72
+ private pendingRpc;
73
+ private stdoutBuffer;
74
+ private _approvalPolicy;
75
+ private _collaborationMode;
76
+ private lastPlanItemText;
77
+ /** Last assistant text message — used as `result` in completion notification. */
78
+ private lastResultText;
79
+ private pendingPlanCompletion;
80
+ /** Queued plan execution text when inputResolve wasn't ready at approval time. */
81
+ private _pendingPlanInput;
82
+ private readonly platform;
83
+ constructor(platform?: NodeJS.Platform);
84
+ get status(): ProcessStatus;
85
+ get isWaitingForInput(): boolean;
86
+ private getMessageModel;
87
+ get sessionId(): string | null;
88
+ get agentNickname(): string | null;
89
+ get agentRole(): string | null;
90
+ get isRunning(): boolean;
91
+ get approvalPolicy(): string;
92
+ /**
93
+ * Update approval policy at runtime.
94
+ * Takes effect on the next `turn/start` RPC call.
95
+ */
96
+ setApprovalPolicy(policy: string): void;
97
+ /**
98
+ * Set collaboration mode ("plan" or "default").
99
+ * Takes effect on the next `turn/start` RPC call.
100
+ */
101
+ setCollaborationMode(mode: "plan" | "default"): void;
102
+ get collaborationMode(): "plan" | "default";
103
+ /**
104
+ * Rename a thread via the app-server RPC.
105
+ * Sends thread/name/set which persists to ~/.codex/session_index.jsonl.
106
+ */
107
+ renameThread(name: string): Promise<void>;
108
+ /**
109
+ * Archive a Codex thread via the app-server `thread/archive` RPC.
110
+ * Accepts an explicit threadId so that historical (non-active) sessions
111
+ * can be archived without requiring a running process.
112
+ */
113
+ archiveThread(threadId: string): Promise<void>;
114
+ listThreads(params?: {
115
+ limit?: number;
116
+ cursor?: string | null;
117
+ cwd?: string;
118
+ searchTerm?: string;
119
+ }): Promise<{
120
+ data: CodexThreadSummary[];
121
+ nextCursor: string | null;
122
+ }>;
123
+ start(projectPath: string, options?: CodexStartOptions): void;
124
+ initializeOnly(projectPath: string): Promise<void>;
125
+ stop(): void;
126
+ private prepareLaunch;
127
+ private launchAppServer;
128
+ interrupt(): void;
129
+ sendInput(text: string): void;
130
+ sendInputWithImages(text: string, images: Array<{
131
+ base64: string;
132
+ mimeType: string;
133
+ }>): void;
134
+ sendInputWithSkill(text: string, skill: {
135
+ name: string;
136
+ path: string;
137
+ }): void;
138
+ approve(toolUseId?: string, _updatedInput?: Record<string, unknown>): void;
139
+ approveAlways(toolUseId?: string): void;
140
+ reject(toolUseId?: string, _message?: string): void;
141
+ answer(toolUseId: string, result: string): void;
142
+ getPendingPermission(toolUseId?: string): {
143
+ toolUseId: string;
144
+ toolName: string;
145
+ input: Record<string, unknown>;
146
+ } | undefined;
147
+ /** Emit a synthetic tool_result so history replay can match it to a permission_request. */
148
+ private emitToolResult;
149
+ private resolvePendingApproval;
150
+ private resolvePendingUserInput;
151
+ /**
152
+ * Plan approved → switch to Default mode and auto-start execution.
153
+ */
154
+ private handlePlanApproved;
155
+ /**
156
+ * Plan rejected → stay in Plan mode and re-plan with feedback.
157
+ */
158
+ private handlePlanRejected;
159
+ private bootstrap;
160
+ private initializeRpcConnection;
161
+ /**
162
+ * Fetch skills from Codex app-server via `skills/list` RPC and emit them
163
+ * as a `supported_commands` system message so the Flutter client can display
164
+ * skill entries alongside built-in slash commands.
165
+ */
166
+ private fetchSkills;
167
+ private runInputLoop;
168
+ private handleStdoutChunk;
169
+ private handleRpcEnvelope;
170
+ private handleRpcResponse;
171
+ private handleServerRequest;
172
+ private handleNotification;
173
+ private handleTurnCompleted;
174
+ private processItemStarted;
175
+ private processItemCompleted;
176
+ private toRpcInput;
177
+ private request;
178
+ private notify;
179
+ private respondToServerRequest;
180
+ private writeEnvelope;
181
+ private rejectAllPending;
182
+ private setStatus;
183
+ private emitMessage;
184
+ private extractToolUseId;
185
+ private handleServerRequestResolved;
186
+ }