@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.
- package/dist/cli.js +102 -5
- 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:
|
|
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;
|