@punkcode/cli 0.1.10 → 0.1.11

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/cli.js +102 -5
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -322,6 +322,7 @@ function runClaude(options, callbacks) {
322
322
 
323
323
  // src/commands/connect.ts
324
324
  import fs3 from "fs";
325
+ import os3 from "os";
325
326
 
326
327
  // src/lib/device-info.ts
327
328
  import os from "os";
@@ -904,6 +905,84 @@ function escapeRegex(str) {
904
905
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
905
906
  }
906
907
 
908
+ // src/lib/directory-discovery.ts
909
+ import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
910
+ async function findProjectDirectory(description, searchRoot, rejections) {
911
+ let prompt2 = `Find up to 3 project directories on this machine that best match: "${description}"
912
+
913
+ Search starting from ${searchRoot}. Rank by relevance. Include a brief reason for each match.`;
914
+ if (rejections?.length) {
915
+ prompt2 += "\n\nThe user rejected these previous suggestions:";
916
+ for (const r of rejections) {
917
+ prompt2 += `
918
+ - ${r.path}${r.feedback ? ` (user said: "${r.feedback}")` : ""}`;
919
+ }
920
+ prompt2 += "\n\nFind different matches based on their feedback.";
921
+ }
922
+ const q = query2({
923
+ prompt: prompt2,
924
+ options: {
925
+ systemPrompt: {
926
+ type: "preset",
927
+ preset: "claude_code",
928
+ append: "IMPORTANT: When searching for directories, always try listing likely parent directories with ls FIRST (e.g. ls ~/github, ls ~/projects). Only use find as a last resort, and always with -maxdepth 3. Never scan the entire home directory."
929
+ },
930
+ permissionMode: "bypassPermissions",
931
+ persistSession: false,
932
+ cwd: searchRoot,
933
+ outputFormat: {
934
+ type: "json_schema",
935
+ schema: {
936
+ type: "object",
937
+ properties: {
938
+ suggestions: {
939
+ type: "array",
940
+ items: {
941
+ type: "object",
942
+ properties: {
943
+ path: { type: "string", description: "Absolute path to the project directory" },
944
+ name: { type: "string", description: "Human-readable project name" },
945
+ reason: { type: "string", description: 'Brief reason why this matches (e.g. "Direct match under github folder")' }
946
+ },
947
+ required: ["path", "name", "reason"]
948
+ }
949
+ }
950
+ },
951
+ required: ["suggestions"]
952
+ }
953
+ }
954
+ }
955
+ });
956
+ try {
957
+ for await (const msg of q) {
958
+ if (msg.type === "result") {
959
+ const resultMsg = msg;
960
+ if (resultMsg.subtype === "success") {
961
+ const structured = resultMsg.structured_output;
962
+ if (structured?.suggestions?.length) {
963
+ logger.info({ count: structured.suggestions.length }, "Project directories found (structured)");
964
+ return structured.suggestions;
965
+ }
966
+ const result = resultMsg.result?.trim();
967
+ if (result && result !== "null" && result.startsWith("/")) {
968
+ const path3 = result.split("\n")[0].trim();
969
+ const name = path3.split("/").pop() ?? path3;
970
+ logger.info({ path: path3, name }, "Project directory found (text fallback)");
971
+ return [{ path: path3, name, reason: "Best match" }];
972
+ }
973
+ logger.info("No matching directories found");
974
+ return [];
975
+ }
976
+ logger.warn({ subtype: resultMsg.subtype }, "Directory search query failed");
977
+ return [];
978
+ }
979
+ }
980
+ } finally {
981
+ q.close();
982
+ }
983
+ return [];
984
+ }
985
+
907
986
  // src/lib/auth.ts
908
987
  import fs2 from "fs";
909
988
  import path2 from "path";
@@ -1066,7 +1145,9 @@ async function connect(server, options) {
1066
1145
  const socket = io(url, {
1067
1146
  path: "/socket.io",
1068
1147
  transports: ["websocket"],
1069
- auth: { token: idToken },
1148
+ auth: (cb) => {
1149
+ refreshIdToken().then((token) => cb({ token })).catch(() => cb({ token: idToken }));
1150
+ },
1070
1151
  reconnection: true,
1071
1152
  reconnectionAttempts: Infinity,
1072
1153
  reconnectionDelay: 1e3,
@@ -1114,6 +1195,11 @@ async function connect(server, options) {
1114
1195
  handleGetCommands(socket, msg);
1115
1196
  }
1116
1197
  });
1198
+ socket.on("find-project", (msg) => {
1199
+ if (msg.type === "find-project") {
1200
+ handleFindProject(socket, msg, defaultCwd);
1201
+ }
1202
+ });
1117
1203
  socket.on("cancel", (msg) => {
1118
1204
  handleCancel(msg.id, activeSessions);
1119
1205
  });
@@ -1130,10 +1216,6 @@ async function connect(server, options) {
1130
1216
  });
1131
1217
  socket.io.on("reconnect_attempt", () => {
1132
1218
  logger.info("Reconnecting...");
1133
- refreshIdToken().then((token) => {
1134
- socket.auth = { token };
1135
- }).catch(() => {
1136
- });
1137
1219
  });
1138
1220
  socket.on("reconnect", (attemptNumber) => {
1139
1221
  logger.info({ attemptNumber }, "Reconnected");
@@ -1318,6 +1400,21 @@ async function handleGetCommands(socket, msg) {
1318
1400
  log2.error({ err }, "Commands error");
1319
1401
  }
1320
1402
  }
1403
+ async function handleFindProject(socket, msg, _defaultCwd) {
1404
+ const { id, description, rootDirectory, rejections } = msg;
1405
+ const searchRoot = rootDirectory ?? os3.homedir();
1406
+ const log2 = createChildLogger({ requestId: id });
1407
+ log2.info({ description, searchRoot }, "Finding project directory...");
1408
+ try {
1409
+ const suggestions = await findProjectDirectory(description, searchRoot, rejections);
1410
+ send(socket, "response", { type: "project_suggestions", suggestions, requestId: id });
1411
+ log2.info({ count: suggestions.length }, "Project suggestions sent");
1412
+ } catch (err) {
1413
+ const message = err instanceof Error ? err.message : String(err);
1414
+ send(socket, "response", { type: "error", message, requestId: id });
1415
+ log2.error({ err }, "Find project error");
1416
+ }
1417
+ }
1321
1418
  async function handleGetContext(socket, msg, defaultCwd) {
1322
1419
  const { id, sessionId } = msg;
1323
1420
  const workingDirectory = msg.workingDirectory ?? defaultCwd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@punkcode/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Control Claude Code from your phone",
5
5
  "type": "module",
6
6
  "bin": {