codeam-cli 1.2.1 → 1.3.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 (2) hide show
  1. package/dist/index.js +70 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24,6 +24,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/commands/start.ts
27
+ var fs3 = __toESM(require("fs"));
28
+ var os4 = __toESM(require("os"));
29
+ var path3 = __toESM(require("path"));
30
+ var import_crypto = require("crypto");
27
31
  var import_picocolors2 = __toESM(require("picocolors"));
28
32
 
29
33
  // src/config.ts
@@ -110,7 +114,7 @@ var import_picocolors = __toESM(require("picocolors"));
110
114
  // package.json
111
115
  var package_default = {
112
116
  name: "codeam-cli",
113
- version: "1.2.1",
117
+ version: "1.3.0",
114
118
  description: "Remote control Claude Code from your mobile device",
115
119
  main: "dist/index.js",
116
120
  bin: {
@@ -681,26 +685,30 @@ var ClaudeService = class {
681
685
  /**
682
686
  * Navigate a React Ink selector to the given 0-based index and confirm.
683
687
  *
684
- * Why not just sendCommand(arrows)? When all arrow keys + Enter arrive in one
685
- * write() call, Node's readline splits them into individual keypress events that
686
- * all fire in the same synchronous run. React Ink's SelectInput captures
687
- * selectedIndex in a closure because React hasn't re-rendered between the
688
- * arrows and the Enter, the closure still sees the initial index (0) when Enter
689
- * fires, so it always submits option 0.
688
+ * Why not sendCommand(arrows + Enter) in one write()?
689
+ * All bytes arrive as one chunk readline fires all keypress events in the
690
+ * same synchronous runReact Ink batches the state updates → each arrow
691
+ * sees selectedIndex=0 final state is still 0 or 1 wrong option selected.
690
692
  *
691
- * Fix: send the arrows first, then wait 150 ms for React to process + re-render,
692
- * then send the confirming Enter.
693
+ * Fix: send each down-arrow in a separate write(), ARROW_MS apart, so React
694
+ * has time to process and re-render between each keystroke. Enter is sent
695
+ * ENTER_MS after the last arrow.
693
696
  */
694
697
  selectOption(index) {
695
- const arrows = "\x1B[B".repeat(Math.max(0, index));
696
- if (arrows) {
697
- this.proc?.stdin?.write(arrows);
698
- setTimeout(() => {
699
- this.proc?.stdin?.write("\r");
700
- }, 150);
701
- } else {
698
+ if (index <= 0) {
702
699
  this.proc?.stdin?.write("\r");
700
+ return;
703
701
  }
702
+ const ARROW_MS = 80;
703
+ const ENTER_MS = 200;
704
+ for (let i = 0; i < index; i++) {
705
+ setTimeout(() => {
706
+ this.proc?.stdin?.write("\x1B[B");
707
+ }, i * ARROW_MS);
708
+ }
709
+ setTimeout(() => {
710
+ this.proc?.stdin?.write("\r");
711
+ }, index * ARROW_MS + ENTER_MS);
704
712
  }
705
713
  /** Send Ctrl+C to Claude. */
706
714
  interrupt() {
@@ -1048,6 +1056,14 @@ var OutputService = class _OutputService {
1048
1056
  };
1049
1057
 
1050
1058
  // src/commands/start.ts
1059
+ function saveFilesTemp(files) {
1060
+ return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
1061
+ const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
1062
+ const tmpPath = path3.join(os4.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
1063
+ fs3.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
1064
+ return tmpPath;
1065
+ });
1066
+ }
1051
1067
  async function start() {
1052
1068
  showIntro();
1053
1069
  const session = getActiveSession();
@@ -1070,7 +1086,25 @@ async function start() {
1070
1086
  switch (cmd.type) {
1071
1087
  case "start_task": {
1072
1088
  const prompt = cmd.payload.prompt;
1073
- if (prompt) sendPrompt(prompt);
1089
+ const files = cmd.payload.files;
1090
+ const effectivePrompt = prompt ?? "";
1091
+ if (files && files.length > 0) {
1092
+ const paths = saveFilesTemp(files);
1093
+ const atRefs = paths.map((p2) => `@${p2}`).join("\n");
1094
+ outputSvc.newTurn();
1095
+ claude.sendCommand(`${atRefs}
1096
+ ${effectivePrompt}`);
1097
+ setTimeout(() => {
1098
+ for (const p2 of paths) {
1099
+ try {
1100
+ fs3.unlinkSync(p2);
1101
+ } catch {
1102
+ }
1103
+ }
1104
+ }, 12e4);
1105
+ } else if (effectivePrompt) {
1106
+ sendPrompt(effectivePrompt);
1107
+ }
1074
1108
  break;
1075
1109
  }
1076
1110
  case "provide_input": {
@@ -1100,7 +1134,25 @@ async function start() {
1100
1134
  const inner = payload.payload ?? {};
1101
1135
  if (cmdType === "start_task") {
1102
1136
  const prompt = inner.prompt;
1103
- if (prompt) sendPrompt(prompt);
1137
+ const files = inner.files;
1138
+ const effectivePrompt = prompt ?? "";
1139
+ if (files && files.length > 0) {
1140
+ const paths = saveFilesTemp(files);
1141
+ const atRefs = paths.map((p2) => `@${p2}`).join("\n");
1142
+ outputSvc.newTurn();
1143
+ claude.sendCommand(`${atRefs}
1144
+ ${effectivePrompt}`);
1145
+ setTimeout(() => {
1146
+ for (const p2 of paths) {
1147
+ try {
1148
+ fs3.unlinkSync(p2);
1149
+ } catch {
1150
+ }
1151
+ }
1152
+ }, 12e4);
1153
+ } else if (effectivePrompt) {
1154
+ sendPrompt(effectivePrompt);
1155
+ }
1104
1156
  } else if (cmdType === "provide_input") {
1105
1157
  const input = inner.input;
1106
1158
  if (input) sendPrompt(input);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Remote control Claude Code from your mobile device",
5
5
  "main": "dist/index.js",
6
6
  "bin": {