forge-remote 0.1.26 → 0.1.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-remote",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Desktop relay for Forge Remote — monitor and control Claude Code sessions from your phone",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/src/cli.js CHANGED
@@ -35,7 +35,9 @@ import { watchWebhookConfigs, stopWatching } from "./webhook-watcher.js";
35
35
  import * as log from "./logger.js";
36
36
  import { checkForUpdate } from "./update-checker.js";
37
37
  import { deployFirestoreRules } from "./google-auth.js";
38
- import { ensureChannelRegistered } from "./channel-setup.js";
38
+ // Channel auto-registration disabled channels require
39
+ // --dangerously-load-development-channels flag during research preview.
40
+ // import { ensureChannelRegistered } from "./channel-setup.js";
39
41
 
40
42
  program
41
43
  .name("forge-remote")
@@ -522,6 +522,7 @@ async function handleSessionCommand(sessionId, commandDoc) {
522
522
  sessionId,
523
523
  data.payload?.prompt,
524
524
  data.payload?.imageBase64,
525
+ data.payload?.model,
525
526
  );
526
527
  break;
527
528
  case "stop_session":
@@ -830,7 +831,7 @@ export async function startNewSession(desktopId, payload) {
830
831
  // Send a follow-up prompt (spawns a new process with --continue)
831
832
  // ---------------------------------------------------------------------------
832
833
 
833
- async function sendFollowUpPrompt(sessionId, prompt, imageBase64) {
834
+ async function sendFollowUpPrompt(sessionId, prompt, imageBase64, model) {
834
835
  const session = activeSessions.get(sessionId);
835
836
  if (!session) {
836
837
  throw new Error("Session not found. It may have ended.");
@@ -872,56 +873,57 @@ async function sendFollowUpPrompt(sessionId, prompt, imageBase64) {
872
873
  session.permissionNeeded = false;
873
874
  session.deniedToolCall = null;
874
875
 
875
- // If an image was attached, save it to a temp file.
876
- let imagePath = null;
877
- if (imageBase64) {
878
- const imageId = `${sessionId.slice(0, 8)}-${Date.now()}`;
879
- imagePath = `/tmp/forge-remote-image-${imageId}.png`;
880
- try {
881
- const imageBuffer = Buffer.from(imageBase64, "base64");
882
- await writeFile(imagePath, imageBuffer);
883
- log.session(
884
- sessionId,
885
- `Saved attached image to ${imagePath} (${imageBuffer.length} bytes)`,
886
- );
887
- } catch (err) {
888
- log.warn(`Failed to save attached image: ${err.message}`);
889
- imagePath = null;
890
- }
891
- }
876
+ // Image attachment feature temporarily disabled the --image flag
877
+ // crashes sessions because the user's Claude Code version doesn't support it.
878
+ // Will re-enable when the flag is supported.
879
+ //
880
+ // let imagePath = null;
881
+ // if (imageBase64) {
882
+ // const imageId = `${sessionId.slice(0, 8)}-${Date.now()}`;
883
+ // imagePath = `/tmp/forge-remote-image-${imageId}.png`;
884
+ // try {
885
+ // const imageBuffer = Buffer.from(imageBase64, "base64");
886
+ // await writeFile(imagePath, imageBuffer);
887
+ // log.session(sessionId, `Saved attached image to ${imagePath} (${imageBuffer.length} bytes)`);
888
+ // } catch (err) {
889
+ // log.warn(`Failed to save attached image: ${err.message}`);
890
+ // imagePath = null;
891
+ // }
892
+ // }
892
893
 
893
894
  // The mobile app writes the user message to Firestore directly (including
894
895
  // image preview) so it shows instantly in the chat UI. The relay does NOT
895
896
  // duplicate this write to avoid showing the message twice.
896
897
  const db = getDb();
897
898
 
898
- // If an image is attached, prepend the file path reference to the prompt
899
- // so Claude Code knows to read the image file.
900
- let finalPrompt = prompt;
901
- if (imagePath) {
902
- finalPrompt = `[The user attached an image from their phone. The image is saved at: ${imagePath} — please read and analyze it.]\n\n${prompt || "What do you see in this image?"}`;
899
+ // If the mobile app sent a model preference, use it for this follow-up.
900
+ if (model && model !== session.model) {
901
+ log.session(sessionId, `Model override: ${session.model} → ${model}`);
902
+ session.model = model;
903
903
  }
904
904
 
905
+ let finalPrompt = prompt;
906
+ // Image path prepending disabled — see note above.
907
+ // if (imagePath) {
908
+ // finalPrompt = `[The user attached an image from their phone. The image is saved at: ${imagePath}]\n\n${prompt || "What do you see in this image?"}`;
909
+ // }
910
+
905
911
  log.session(
906
912
  sessionId,
907
- `Follow-up prompt: "${finalPrompt.slice(0, 80)}${finalPrompt.length > 80 ? "..." : ""}"${imagePath ? " [with image]" : ""}`,
913
+ `Follow-up prompt: "${finalPrompt.slice(0, 80)}${finalPrompt.length > 80 ? "..." : ""}"`,
908
914
  );
909
915
 
910
916
  // Run Claude with --continue to pick up conversation history.
911
917
  await runClaudeProcess(sessionId, finalPrompt);
912
918
 
913
- // Clean up the temp image file after the process has started.
914
- if (imagePath) {
915
- // Delay cleanup slightly to ensure Claude has read the file.
916
- setTimeout(async () => {
917
- try {
918
- await unlink(imagePath);
919
- log.session(sessionId, `Cleaned up temp image: ${imagePath}`);
920
- } catch {
921
- // File may already be gone — ignore.
922
- }
923
- }, 30_000);
924
- }
919
+ // Image temp file cleanup disabled see note above.
920
+ // if (imagePath) {
921
+ // setTimeout(async () => {
922
+ // try {
923
+ // await unlink(imagePath);
924
+ // } catch { }
925
+ // }, 30_000);
926
+ // }
925
927
  }
926
928
 
927
929
  // ---------------------------------------------------------------------------
@@ -968,6 +970,15 @@ async function runClaudeProcess(sessionId, prompt) {
968
970
  );
969
971
 
970
972
  const spawnEnv = { ...shellEnv, ...adapter.getExtraEnv() };
973
+
974
+ // NOTE: Claude Code permissions for the .claude/ directory.
975
+ // If users get permission prompts for writing to .claude/ (e.g. CLAUDE.md,
976
+ // settings.json), they need to configure this in their Claude Code settings.
977
+ // This is a Claude Code configuration issue — the relay cannot pass
978
+ // --allowedTools or --permissions flags to auto-allow .claude/ writes.
979
+ // Users should add `.claude/` to their allowed paths in their Claude Code
980
+ // settings or use the "Always Allow" option when prompted.
981
+
971
982
  const claudeProcess = spawn(binary, args, {
972
983
  cwd: session.projectPath,
973
984
  env: spawnEnv,