@punkcode/cli
Advanced tools
+102
-5
@@ -325,2 +325,3 @@ #!/usr/bin/env node | ||
| import fs3 from "fs"; | ||
| import os3 from "os"; | ||
@@ -908,2 +909,80 @@ // src/lib/device-info.ts | ||
| // src/lib/directory-discovery.ts | ||
| import { query as query2 } from "@anthropic-ai/claude-agent-sdk"; | ||
| async function findProjectDirectory(description, searchRoot, rejections) { | ||
| let prompt2 = `Find up to 3 project directories on this machine that best match: "${description}" | ||
| Search starting from ${searchRoot}. Rank by relevance. Include a brief reason for each match.`; | ||
| if (rejections?.length) { | ||
| prompt2 += "\n\nThe user rejected these previous suggestions:"; | ||
| for (const r of rejections) { | ||
| prompt2 += ` | ||
| - ${r.path}${r.feedback ? ` (user said: "${r.feedback}")` : ""}`; | ||
| } | ||
| prompt2 += "\n\nFind different matches based on their feedback."; | ||
| } | ||
| const q = query2({ | ||
| prompt: prompt2, | ||
| options: { | ||
| systemPrompt: { | ||
| type: "preset", | ||
| preset: "claude_code", | ||
| 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." | ||
| }, | ||
| permissionMode: "bypassPermissions", | ||
| persistSession: false, | ||
| cwd: searchRoot, | ||
| outputFormat: { | ||
| type: "json_schema", | ||
| schema: { | ||
| type: "object", | ||
| properties: { | ||
| suggestions: { | ||
| type: "array", | ||
| items: { | ||
| type: "object", | ||
| properties: { | ||
| path: { type: "string", description: "Absolute path to the project directory" }, | ||
| name: { type: "string", description: "Human-readable project name" }, | ||
| reason: { type: "string", description: 'Brief reason why this matches (e.g. "Direct match under github folder")' } | ||
| }, | ||
| required: ["path", "name", "reason"] | ||
| } | ||
| } | ||
| }, | ||
| required: ["suggestions"] | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| try { | ||
| for await (const msg of q) { | ||
| if (msg.type === "result") { | ||
| const resultMsg = msg; | ||
| if (resultMsg.subtype === "success") { | ||
| const structured = resultMsg.structured_output; | ||
| if (structured?.suggestions?.length) { | ||
| logger.info({ count: structured.suggestions.length }, "Project directories found (structured)"); | ||
| return structured.suggestions; | ||
| } | ||
| const result = resultMsg.result?.trim(); | ||
| if (result && result !== "null" && result.startsWith("/")) { | ||
| const path3 = result.split("\n")[0].trim(); | ||
| const name = path3.split("/").pop() ?? path3; | ||
| logger.info({ path: path3, name }, "Project directory found (text fallback)"); | ||
| return [{ path: path3, name, reason: "Best match" }]; | ||
| } | ||
| logger.info("No matching directories found"); | ||
| return []; | ||
| } | ||
| logger.warn({ subtype: resultMsg.subtype }, "Directory search query failed"); | ||
| return []; | ||
| } | ||
| } | ||
| } finally { | ||
| q.close(); | ||
| } | ||
| return []; | ||
| } | ||
| // src/lib/auth.ts | ||
@@ -1071,3 +1150,5 @@ import fs2 from "fs"; | ||
| transports: ["websocket"], | ||
| auth: { token: idToken }, | ||
| auth: (cb) => { | ||
| refreshIdToken().then((token) => cb({ token })).catch(() => cb({ token: idToken })); | ||
| }, | ||
| reconnection: true, | ||
@@ -1120,2 +1201,7 @@ reconnectionAttempts: Infinity, | ||
| }); | ||
| socket.on("find-project", (msg) => { | ||
| if (msg.type === "find-project") { | ||
| handleFindProject(socket, msg, defaultCwd); | ||
| } | ||
| }); | ||
| socket.on("cancel", (msg) => { | ||
@@ -1137,6 +1223,2 @@ handleCancel(msg.id, activeSessions); | ||
| logger.info("Reconnecting..."); | ||
| refreshIdToken().then((token) => { | ||
| socket.auth = { token }; | ||
| }).catch(() => { | ||
| }); | ||
| }); | ||
@@ -1326,2 +1408,17 @@ socket.on("reconnect", (attemptNumber) => { | ||
| } | ||
| async function handleFindProject(socket, msg, _defaultCwd) { | ||
| const { id, description, rootDirectory, rejections } = msg; | ||
| const searchRoot = rootDirectory ?? os3.homedir(); | ||
| const log2 = createChildLogger({ requestId: id }); | ||
| log2.info({ description, searchRoot }, "Finding project directory..."); | ||
| try { | ||
| const suggestions = await findProjectDirectory(description, searchRoot, rejections); | ||
| send(socket, "response", { type: "project_suggestions", suggestions, requestId: id }); | ||
| log2.info({ count: suggestions.length }, "Project suggestions sent"); | ||
| } catch (err) { | ||
| const message = err instanceof Error ? err.message : String(err); | ||
| send(socket, "response", { type: "error", message, requestId: id }); | ||
| log2.error({ err }, "Find project error"); | ||
| } | ||
| } | ||
| async function handleGetContext(socket, msg, defaultCwd) { | ||
@@ -1328,0 +1425,0 @@ const { id, sessionId } = msg; |
+1
-1
| { | ||
| "name": "@punkcode/cli", | ||
| "version": "0.1.10", | ||
| "version": "0.1.11", | ||
| "description": "Control Claude Code from your phone", | ||
@@ -5,0 +5,0 @@ "type": "module", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
55681
7.6%1505
6.74%