staklink 0.4.3 → 0.4.5
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/proxy-server.cjs +169 -25
- package/dist/staklink-cli.cjs +27 -27
- package/package.json +1 -1
package/dist/proxy-server.cjs
CHANGED
|
@@ -60777,7 +60777,7 @@ var SSEManager = class {
|
|
|
60777
60777
|
var sseManager = new SSEManager();
|
|
60778
60778
|
|
|
60779
60779
|
// src/proxy/version.ts
|
|
60780
|
-
var VERSION = "0.4.
|
|
60780
|
+
var VERSION = "0.4.5";
|
|
60781
60781
|
|
|
60782
60782
|
// node_modules/uuid/dist/esm/stringify.js
|
|
60783
60783
|
var byteToHex = [];
|
|
@@ -60950,7 +60950,12 @@ var fs8 = __toESM(require("fs"), 1);
|
|
|
60950
60950
|
var path7 = __toESM(require("path"), 1);
|
|
60951
60951
|
var os = __toESM(require("os"), 1);
|
|
60952
60952
|
|
|
60953
|
-
// src/agent/
|
|
60953
|
+
// src/agent/system_prompt.ts
|
|
60954
|
+
var SYSTEM_CORE = `You are a software systems expert. You are working on a cloud dev server (code-server) that is running a software project. The user's application is being run with pm2. You can use the pm2 cli to inspect the running processes. There may also be supporting services running as docker containers. Because you are running on a cloud server, certain operation may not be possible, such as launching a desktop application, or opening a browser window. The user can see the running application from the pm2 service called "frontend" in an iframe on their end.
|
|
60955
|
+
|
|
60956
|
+
Do not commit or push code to github. That is handled by a workflow after you are done working.
|
|
60957
|
+
|
|
60958
|
+
`;
|
|
60954
60959
|
var SYSTEM_SUFFIX = `
|
|
60955
60960
|
You can ignore the .pod-config directory if you see it, its just config stuff
|
|
60956
60961
|
|
|
@@ -137820,7 +137825,8 @@ async function runAgent({
|
|
|
137820
137825
|
const env2 = goose_env(apiKey, model);
|
|
137821
137826
|
console.log("RUN goose with env", env2);
|
|
137822
137827
|
const cleanPrompt = sanitizeShellArg(prompt);
|
|
137823
|
-
let system =
|
|
137828
|
+
let system = SYSTEM_CORE;
|
|
137829
|
+
system += system_prompt ? sanitizeShellArg(system_prompt) + "\n\n" : "";
|
|
137824
137830
|
system += SYSTEM_SUFFIX;
|
|
137825
137831
|
system = sanitizeShellArg(system);
|
|
137826
137832
|
console.log("Using Goose CLI", cleanPrompt, system);
|
|
@@ -139430,7 +139436,8 @@ async function runAgent3({
|
|
|
139430
139436
|
session,
|
|
139431
139437
|
summarize
|
|
139432
139438
|
}) {
|
|
139433
|
-
let system =
|
|
139439
|
+
let system = SYSTEM_CORE;
|
|
139440
|
+
system += system_prompt ? system_prompt + "\n\n" : "";
|
|
139434
139441
|
system += SYSTEM_SUFFIX;
|
|
139435
139442
|
console.log("Codex agent using API key:", apiKey ? `${apiKey.substring(0, 8)}...` : "MISSING");
|
|
139436
139443
|
if (apiKey) {
|
|
@@ -139463,7 +139470,7 @@ __export(repair_exports, {
|
|
|
139463
139470
|
makeRepairPrompt: () => makeRepairPrompt,
|
|
139464
139471
|
parseXML: () => parseXML
|
|
139465
139472
|
});
|
|
139466
|
-
var SYSTEM2 =
|
|
139473
|
+
var SYSTEM2 = SYSTEM_CORE + `Your job is to help set up the development environment for a software project. Fix the user's pm2 config and/or docker-compose files, and use the pm2 and docker cli to get the project running. YOUR GOAL IS TO THE GET THE frontend APP IN THE PM2 CONFIG FILE TO RUN CORRECTLY! Other apps and docker containers are only supporting services. You can restart the pm2 environment with "npx -y staklink reload" after making changes to the pm2 config or docker-compose files.
|
|
139467
139474
|
|
|
139468
139475
|
When you have gotten the frontend running, or gotten as far as you can, respond to the user by saying either "<status>COMPLETE</status>" or "<status>FAILED</status>". If COMPLETE, then tell the user the fixed config files (put the exact raw content of the files in the XML tags, no extra text like triple backticks or language label). FOR YOUR FINAL TEXT RESPONSE, USE THE THE FOLLOWING XML FORMAT:
|
|
139469
139476
|
|
|
@@ -139988,6 +139995,22 @@ var SCREENSHOT_DIR = import_path3.default.join(
|
|
|
139988
139995
|
"tmp",
|
|
139989
139996
|
"screenshots"
|
|
139990
139997
|
);
|
|
139998
|
+
async function cleanupAllScreenshots() {
|
|
139999
|
+
try {
|
|
140000
|
+
const entries = await import_promises2.default.readdir(SCREENSHOT_DIR);
|
|
140001
|
+
const pngs = entries.filter((e) => e.endsWith(".png"));
|
|
140002
|
+
await Promise.all(
|
|
140003
|
+
pngs.map(
|
|
140004
|
+
(file3) => import_promises2.default.unlink(import_path3.default.join(SCREENSHOT_DIR, file3)).catch(() => {
|
|
140005
|
+
})
|
|
140006
|
+
)
|
|
140007
|
+
);
|
|
140008
|
+
if (pngs.length > 0) {
|
|
140009
|
+
log(`Cleaned up ${pngs.length} leftover screenshot(s)`);
|
|
140010
|
+
}
|
|
140011
|
+
} catch {
|
|
140012
|
+
}
|
|
140013
|
+
}
|
|
139991
140014
|
async function collectScreenshots(since) {
|
|
139992
140015
|
try {
|
|
139993
140016
|
const entries = await import_promises2.default.readdir(SCREENSHOT_DIR);
|
|
@@ -140001,6 +140024,10 @@ async function collectScreenshots(since) {
|
|
|
140001
140024
|
}
|
|
140002
140025
|
const buf = await import_promises2.default.readFile(filePath);
|
|
140003
140026
|
results.push({ filename: file3, base64: `data:image/png;base64,${buf.toString("base64")}` });
|
|
140027
|
+
try {
|
|
140028
|
+
await import_promises2.default.unlink(filePath);
|
|
140029
|
+
} catch {
|
|
140030
|
+
}
|
|
140004
140031
|
}
|
|
140005
140032
|
return results;
|
|
140006
140033
|
} catch {
|
|
@@ -141083,6 +141110,97 @@ Stderr: ${error88.stderr}`
|
|
|
141083
141110
|
};
|
|
141084
141111
|
|
|
141085
141112
|
// src/proxy/git_actions.ts
|
|
141113
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
141114
|
+
".png",
|
|
141115
|
+
".jpg",
|
|
141116
|
+
".jpeg",
|
|
141117
|
+
".gif",
|
|
141118
|
+
".bmp",
|
|
141119
|
+
".webp",
|
|
141120
|
+
".ico",
|
|
141121
|
+
".svg",
|
|
141122
|
+
".tiff",
|
|
141123
|
+
".tif",
|
|
141124
|
+
".avif"
|
|
141125
|
+
]);
|
|
141126
|
+
var MIME_TYPES = {
|
|
141127
|
+
".png": "image/png",
|
|
141128
|
+
".jpg": "image/jpeg",
|
|
141129
|
+
".jpeg": "image/jpeg",
|
|
141130
|
+
".gif": "image/gif",
|
|
141131
|
+
".bmp": "image/bmp",
|
|
141132
|
+
".webp": "image/webp",
|
|
141133
|
+
".ico": "image/x-icon",
|
|
141134
|
+
".svg": "image/svg+xml",
|
|
141135
|
+
".tiff": "image/tiff",
|
|
141136
|
+
".tif": "image/tiff",
|
|
141137
|
+
".avif": "image/avif"
|
|
141138
|
+
};
|
|
141139
|
+
function isImageFile(filePath) {
|
|
141140
|
+
return IMAGE_EXTENSIONS.has(import_path4.default.extname(filePath).toLowerCase());
|
|
141141
|
+
}
|
|
141142
|
+
async function binaryDiffContent(repo, filePath, action) {
|
|
141143
|
+
const isBinary = await isGitBinaryFile(repo, filePath);
|
|
141144
|
+
if (!isBinary) {
|
|
141145
|
+
return null;
|
|
141146
|
+
}
|
|
141147
|
+
if (action === "delete") {
|
|
141148
|
+
if (isImageFile(filePath)) {
|
|
141149
|
+
return `Binary image file deleted: ${filePath}`;
|
|
141150
|
+
}
|
|
141151
|
+
return `Binary file deleted: ${filePath}`;
|
|
141152
|
+
}
|
|
141153
|
+
if (isImageFile(filePath)) {
|
|
141154
|
+
try {
|
|
141155
|
+
const absPath = import_path4.default.join(repo.printcwd(), filePath);
|
|
141156
|
+
const buffer = import_fs4.default.readFileSync(absPath);
|
|
141157
|
+
const ext2 = import_path4.default.extname(filePath).toLowerCase();
|
|
141158
|
+
const mime = MIME_TYPES[ext2] || "application/octet-stream";
|
|
141159
|
+
const b64 = buffer.toString("base64");
|
|
141160
|
+
return `--- ${action === "create" ? "/dev/null" : `a/${filePath}`}
|
|
141161
|
+
+++ b/${filePath}
|
|
141162
|
+
Binary image file (${mime}, ${formatBytes(buffer.length)})
|
|
141163
|
+
data:${mime};base64,${b64}`;
|
|
141164
|
+
} catch {
|
|
141165
|
+
return `Binary image file changed: ${filePath} (could not read file)`;
|
|
141166
|
+
}
|
|
141167
|
+
}
|
|
141168
|
+
return `Binary file changed: ${filePath}`;
|
|
141169
|
+
}
|
|
141170
|
+
async function isGitBinaryFile(repo, filePath) {
|
|
141171
|
+
try {
|
|
141172
|
+
const numstat = await repo.execCommand(
|
|
141173
|
+
`git diff --numstat HEAD -- "${filePath}"`
|
|
141174
|
+
);
|
|
141175
|
+
if (numstat.trim().startsWith("- -")) {
|
|
141176
|
+
return true;
|
|
141177
|
+
}
|
|
141178
|
+
} catch {
|
|
141179
|
+
}
|
|
141180
|
+
try {
|
|
141181
|
+
const absPath = import_path4.default.join(repo.printcwd(), filePath);
|
|
141182
|
+
const buf = Buffer.alloc(8192);
|
|
141183
|
+
const fd = import_fs4.default.openSync(absPath, "r");
|
|
141184
|
+
const bytesRead = import_fs4.default.readSync(fd, buf, 0, 8192, 0);
|
|
141185
|
+
import_fs4.default.closeSync(fd);
|
|
141186
|
+
for (let i = 0; i < bytesRead; i++) {
|
|
141187
|
+
if (buf[i] === 0) {
|
|
141188
|
+
return true;
|
|
141189
|
+
}
|
|
141190
|
+
}
|
|
141191
|
+
} catch {
|
|
141192
|
+
}
|
|
141193
|
+
return false;
|
|
141194
|
+
}
|
|
141195
|
+
function formatBytes(bytes) {
|
|
141196
|
+
if (bytes < 1024) {
|
|
141197
|
+
return `${bytes} B`;
|
|
141198
|
+
}
|
|
141199
|
+
if (bytes < 1024 * 1024) {
|
|
141200
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
141201
|
+
}
|
|
141202
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
141203
|
+
}
|
|
141086
141204
|
async function handleBranchDiff(req, res) {
|
|
141087
141205
|
try {
|
|
141088
141206
|
const results = [];
|
|
@@ -141134,12 +141252,17 @@ async function handleBranchDiff(req, res) {
|
|
|
141134
141252
|
action = "modify";
|
|
141135
141253
|
}
|
|
141136
141254
|
let content = "";
|
|
141137
|
-
|
|
141138
|
-
|
|
141139
|
-
|
|
141140
|
-
|
|
141141
|
-
|
|
141142
|
-
|
|
141255
|
+
const binaryContent = await binaryDiffContent(repo, filePath, action);
|
|
141256
|
+
if (binaryContent !== null) {
|
|
141257
|
+
content = binaryContent;
|
|
141258
|
+
} else {
|
|
141259
|
+
try {
|
|
141260
|
+
content = await repo.execCommand(
|
|
141261
|
+
`git diff ${mergeBase} -- "${filePath}"`
|
|
141262
|
+
);
|
|
141263
|
+
} catch (error88) {
|
|
141264
|
+
warn(`Error getting branch diff for ${filePath}:`, error88);
|
|
141265
|
+
}
|
|
141143
141266
|
}
|
|
141144
141267
|
results.push({
|
|
141145
141268
|
file: `${repoName}/${filePath}`,
|
|
@@ -141190,15 +141313,24 @@ async function handleDiff(_req, res) {
|
|
|
141190
141313
|
action = "modify";
|
|
141191
141314
|
}
|
|
141192
141315
|
let content = "";
|
|
141193
|
-
|
|
141194
|
-
|
|
141195
|
-
|
|
141196
|
-
|
|
141197
|
-
|
|
141198
|
-
|
|
141316
|
+
const binaryContent = await binaryDiffContent(repo, filePath, action);
|
|
141317
|
+
if (binaryContent !== null) {
|
|
141318
|
+
content = binaryContent;
|
|
141319
|
+
} else {
|
|
141320
|
+
try {
|
|
141321
|
+
if (action === "delete") {
|
|
141322
|
+
content = await repo.execCommand(
|
|
141323
|
+
`git diff HEAD -- "${filePath}"`
|
|
141324
|
+
);
|
|
141325
|
+
} else {
|
|
141326
|
+
log("Getting diff for", filePath);
|
|
141327
|
+
content = await repo.execCommand(
|
|
141328
|
+
`git diff HEAD -- "${filePath}"`
|
|
141329
|
+
);
|
|
141330
|
+
}
|
|
141331
|
+
} catch (error88) {
|
|
141332
|
+
warn(`Error getting diff for ${filePath}:`, error88);
|
|
141199
141333
|
}
|
|
141200
|
-
} catch (error88) {
|
|
141201
|
-
warn(`Error getting diff for ${filePath}:`, error88);
|
|
141202
141334
|
}
|
|
141203
141335
|
results.push({
|
|
141204
141336
|
file: `${repoName}/${filePath}`,
|
|
@@ -141211,15 +141343,24 @@ async function handleDiff(_req, res) {
|
|
|
141211
141343
|
const untrackedLines = untrackedOutput.trim().split("\n").filter((line) => line);
|
|
141212
141344
|
for (const filePath of untrackedLines) {
|
|
141213
141345
|
let content = "";
|
|
141214
|
-
|
|
141215
|
-
|
|
141216
|
-
|
|
141217
|
-
|
|
141346
|
+
const binaryContent = await binaryDiffContent(
|
|
141347
|
+
repo,
|
|
141348
|
+
filePath,
|
|
141349
|
+
"create"
|
|
141350
|
+
);
|
|
141351
|
+
if (binaryContent !== null) {
|
|
141352
|
+
content = binaryContent;
|
|
141353
|
+
} else {
|
|
141354
|
+
try {
|
|
141355
|
+
const fileContent = await repo.execCommand(`cat "${filePath}"`);
|
|
141356
|
+
const lines2 = fileContent.split("\n");
|
|
141357
|
+
content = `--- /dev/null
|
|
141218
141358
|
+++ b/${filePath}
|
|
141219
141359
|
@@ -0,0 +1,${lines2.length} @@
|
|
141220
141360
|
${lines2.map((line) => "+" + line).join("\n")}`;
|
|
141221
|
-
|
|
141222
|
-
|
|
141361
|
+
} catch (error88) {
|
|
141362
|
+
warn(`Error reading untracked file ${filePath}:`, error88);
|
|
141363
|
+
}
|
|
141223
141364
|
}
|
|
141224
141365
|
results.push({
|
|
141225
141366
|
file: `${repoName}/${filePath}`,
|
|
@@ -142495,6 +142636,9 @@ ${logs}
|
|
|
142495
142636
|
|
|
142496
142637
|
// src/proxy/main.ts
|
|
142497
142638
|
console.log("Starting staklink proxy server...");
|
|
142639
|
+
cleanupAllScreenshots().catch((err) => {
|
|
142640
|
+
warn("Screenshot cleanup failed:", err);
|
|
142641
|
+
});
|
|
142498
142642
|
startProxyServer().catch((err) => {
|
|
142499
142643
|
error("Failed to start proxy server:", err);
|
|
142500
142644
|
process.exit(1);
|
package/dist/staklink-cli.cjs
CHANGED
|
@@ -10967,7 +10967,7 @@ var glob = Object.assign(glob_, {
|
|
|
10967
10967
|
glob.glob = glob;
|
|
10968
10968
|
|
|
10969
10969
|
// src/proxy/version.ts
|
|
10970
|
-
var VERSION = "0.4.
|
|
10970
|
+
var VERSION = "0.4.5";
|
|
10971
10971
|
|
|
10972
10972
|
// src/deps.ts
|
|
10973
10973
|
var import_child_process = require("child_process");
|
|
@@ -10977,11 +10977,18 @@ var import_os = require("os");
|
|
|
10977
10977
|
var import_path2 = require("path");
|
|
10978
10978
|
var execAsync = (0, import_util2.promisify)(import_child_process.exec);
|
|
10979
10979
|
var GOOSE_VERSION = "1.22.0";
|
|
10980
|
+
var SKILLS = [
|
|
10981
|
+
{ name: "agent-browser", repo: "https://github.com/vercel-labs/agent-browser" },
|
|
10982
|
+
{ name: "code-simplifier", repo: "https://github.com/getsentry/skills" },
|
|
10983
|
+
{ name: "frontend-design", repo: "https://github.com/anthropics/claude-code" }
|
|
10984
|
+
];
|
|
10980
10985
|
async function ensureDepsInstalled() {
|
|
10981
10986
|
await ensureGooseInstalled();
|
|
10982
10987
|
await ensureAgentBrowserInstalled();
|
|
10983
|
-
|
|
10984
|
-
|
|
10988
|
+
for (const skill of SKILLS) {
|
|
10989
|
+
await ensureSkillInstalled(skill.name, skill.repo);
|
|
10990
|
+
await migrateSkill(skill.name);
|
|
10991
|
+
}
|
|
10985
10992
|
}
|
|
10986
10993
|
async function ensureGooseInstalled() {
|
|
10987
10994
|
try {
|
|
@@ -11032,42 +11039,35 @@ async function installAgentBrowser() {
|
|
|
11032
11039
|
console.error("\u26A0\uFE0F Failed to install agent-browser:", error2);
|
|
11033
11040
|
}
|
|
11034
11041
|
}
|
|
11035
|
-
|
|
11036
|
-
var AGENT_BROWSER_SKILL_REPO = "https://github.com/vercel-labs/agent-browser";
|
|
11037
|
-
async function ensureAgentBrowserSkillInstalled() {
|
|
11038
|
-
const skillPath = (0, import_path2.join)((0, import_os.homedir)(), ".config", "agents", "skills", AGENT_BROWSER_SKILL_NAME);
|
|
11039
|
-
if ((0, import_fs3.existsSync)(skillPath)) {
|
|
11040
|
-
console.log(`\u2705 Skill "${AGENT_BROWSER_SKILL_NAME}" is already installed`);
|
|
11041
|
-
return;
|
|
11042
|
-
}
|
|
11043
|
-
console.log(`\u{1F4E6} Installing ${AGENT_BROWSER_SKILL_NAME} skill...`);
|
|
11044
|
-
await installAgentBrowserSkill();
|
|
11045
|
-
}
|
|
11046
|
-
async function migrateAgentBrowserSkill() {
|
|
11042
|
+
async function migrateSkill(skillName) {
|
|
11047
11043
|
const home = (0, import_os.homedir)();
|
|
11048
|
-
const oldPath = (0, import_path2.join)(home, ".agents", "skills",
|
|
11044
|
+
const oldPath = (0, import_path2.join)(home, ".agents", "skills", skillName);
|
|
11049
11045
|
const newDir = (0, import_path2.join)(home, ".config", "agents", "skills");
|
|
11050
|
-
const newPath = (0, import_path2.join)(newDir,
|
|
11046
|
+
const newPath = (0, import_path2.join)(newDir, skillName);
|
|
11051
11047
|
if (!(0, import_fs3.existsSync)(oldPath) || (0, import_fs3.existsSync)(newPath)) {
|
|
11052
11048
|
return;
|
|
11053
11049
|
}
|
|
11054
11050
|
try {
|
|
11055
|
-
console.log(
|
|
11051
|
+
console.log(`\u{1F504} Copying ${skillName} skill to new location...`);
|
|
11056
11052
|
await execAsync(`mkdir -p "${newDir}"`);
|
|
11057
|
-
await execAsync(`
|
|
11058
|
-
console.log(
|
|
11053
|
+
await execAsync(`cp -r "${oldPath}" "${newPath}"`);
|
|
11054
|
+
console.log(`\u2705 ${skillName} skill copied to new location`);
|
|
11059
11055
|
} catch (error2) {
|
|
11060
|
-
console.error(
|
|
11056
|
+
console.error(`\u26A0\uFE0F Failed to copy ${skillName} skill:`, error2);
|
|
11061
11057
|
}
|
|
11062
11058
|
}
|
|
11063
|
-
async function
|
|
11059
|
+
async function ensureSkillInstalled(skillName, repo) {
|
|
11060
|
+
const skillPath = (0, import_path2.join)((0, import_os.homedir)(), ".config", "agents", "skills", skillName);
|
|
11061
|
+
if ((0, import_fs3.existsSync)(skillPath)) {
|
|
11062
|
+
console.log(`\u2705 Skill "${skillName}" is already installed`);
|
|
11063
|
+
return;
|
|
11064
|
+
}
|
|
11065
|
+
console.log(`\u{1F4E6} Installing ${skillName} skill...`);
|
|
11064
11066
|
try {
|
|
11065
|
-
await execAsync(
|
|
11066
|
-
|
|
11067
|
-
);
|
|
11068
|
-
console.log(`\u2705 Skill "${AGENT_BROWSER_SKILL_NAME}" installed successfully`);
|
|
11067
|
+
await execAsync(`npx skills add ${repo} --skill ${skillName} -g -y`);
|
|
11068
|
+
console.log(`\u2705 Skill "${skillName}" installed successfully`);
|
|
11069
11069
|
} catch (error2) {
|
|
11070
|
-
console.error(`\u26A0\uFE0F Failed to install ${
|
|
11070
|
+
console.error(`\u26A0\uFE0F Failed to install ${skillName} skill:`, error2);
|
|
11071
11071
|
}
|
|
11072
11072
|
}
|
|
11073
11073
|
|