@tickernelz/paperclip-pro-adapter-cursor-local 2026.925.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.
- package/LICENSE +22 -0
- package/dist/cli/format-event.d.ts +2 -0
- package/dist/cli/format-event.d.ts.map +1 -0
- package/dist/cli/format-event.js +296 -0
- package/dist/cli/format-event.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/server/execute.d.ts +15 -0
- package/dist/server/execute.d.ts.map +1 -0
- package/dist/server/execute.js +640 -0
- package/dist/server/execute.js.map +1 -0
- package/dist/server/execute.remote.test.d.ts +2 -0
- package/dist/server/execute.remote.test.d.ts.map +1 -0
- package/dist/server/execute.remote.test.js +284 -0
- package/dist/server/execute.remote.test.js.map +1 -0
- package/dist/server/execute.test.d.ts +2 -0
- package/dist/server/execute.test.d.ts.map +1 -0
- package/dist/server/execute.test.js +294 -0
- package/dist/server/execute.test.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +62 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/parse.d.ts +13 -0
- package/dist/server/parse.d.ts.map +1 -0
- package/dist/server/parse.js +139 -0
- package/dist/server/parse.js.map +1 -0
- package/dist/server/remote-command.d.ts +20 -0
- package/dist/server/remote-command.d.ts.map +1 -0
- package/dist/server/remote-command.js +172 -0
- package/dist/server/remote-command.js.map +1 -0
- package/dist/server/remote-command.test.d.ts +2 -0
- package/dist/server/remote-command.test.d.ts.map +1 -0
- package/dist/server/remote-command.test.js +123 -0
- package/dist/server/remote-command.test.js.map +1 -0
- package/dist/server/skills.d.ts +8 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +69 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/test.d.ts +10 -0
- package/dist/server/test.d.ts.map +1 -0
- package/dist/server/test.js +334 -0
- package/dist/server/test.js.map +1 -0
- package/dist/server/test.test.d.ts +2 -0
- package/dist/server/test.test.d.ts.map +1 -0
- package/dist/server/test.test.js +116 -0
- package/dist/server/test.test.js.map +1 -0
- package/dist/shared/stream.d.ts +5 -0
- package/dist/shared/stream.d.ts.map +1 -0
- package/dist/shared/stream.js +13 -0
- package/dist/shared/stream.js.map +1 -0
- package/dist/shared/trust.d.ts +2 -0
- package/dist/shared/trust.d.ts.map +1 -0
- package/dist/shared/trust.js +7 -0
- package/dist/shared/trust.js.map +1 -0
- package/dist/ui/build-config.d.ts +3 -0
- package/dist/ui/build-config.d.ts.map +1 -0
- package/dist/ui/build-config.js +36 -0
- package/dist/ui/build-config.js.map +1 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/parse-stdout.d.ts +3 -0
- package/dist/ui/parse-stdout.d.ts.map +1 -0
- package/dist/ui/parse-stdout.js +378 -0
- package/dist/ui/parse-stdout.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { runAdapterExecutionTargetShellCommand, } from "@tickernelz/paperclip-pro-adapter-utils/execution-target";
|
|
3
|
+
import { ensurePathInEnv } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
|
|
4
|
+
const DEFAULT_CURSOR_COMMAND_BASENAMES = new Set(["agent", "cursor-agent"]);
|
|
5
|
+
// `.local/bin` first because the official Cursor Agent installer drops the
|
|
6
|
+
// binary there; `.cursor/bin` is a secondary location used by some older
|
|
7
|
+
// installs. The order also defines the prepended `PATH` order surfaced to the
|
|
8
|
+
// adapter.
|
|
9
|
+
const CURSOR_SANDBOX_BIN_DIRS = [
|
|
10
|
+
path.posix.join(".local", "bin"),
|
|
11
|
+
path.posix.join(".cursor", "bin"),
|
|
12
|
+
];
|
|
13
|
+
function commandBasename(command) {
|
|
14
|
+
return command.trim().split(/[\\/]/).pop()?.toLowerCase() ?? "";
|
|
15
|
+
}
|
|
16
|
+
function hasPathSeparator(command) {
|
|
17
|
+
return command.includes("/") || command.includes("\\");
|
|
18
|
+
}
|
|
19
|
+
function prependPosixPathEntry(pathValue, entry) {
|
|
20
|
+
const parts = pathValue.split(":").filter(Boolean);
|
|
21
|
+
if (parts.includes(entry))
|
|
22
|
+
return pathValue;
|
|
23
|
+
const cleaned = parts.join(":");
|
|
24
|
+
return cleaned.length > 0 ? `${entry}:${cleaned}` : entry;
|
|
25
|
+
}
|
|
26
|
+
function prependPosixPathEntries(pathValue, entries) {
|
|
27
|
+
return entries.reduceRight((value, entry) => prependPosixPathEntry(value, entry), pathValue);
|
|
28
|
+
}
|
|
29
|
+
function preferredSandboxCommandBasenames(command) {
|
|
30
|
+
const basename = commandBasename(command);
|
|
31
|
+
if (!DEFAULT_CURSOR_COMMAND_BASENAMES.has(basename))
|
|
32
|
+
return [];
|
|
33
|
+
return basename === "cursor-agent"
|
|
34
|
+
? ["cursor-agent", "agent"]
|
|
35
|
+
: ["agent", "cursor-agent"];
|
|
36
|
+
}
|
|
37
|
+
function candidateSandboxCommandPaths(homeDir, basenames) {
|
|
38
|
+
// Iterate dirs first, then basenames within each dir, so directory
|
|
39
|
+
// preference (CURSOR_SANDBOX_BIN_DIRS order) wins over basename
|
|
40
|
+
// preference. Both basenames inside `.local/bin` are checked before
|
|
41
|
+
// falling through to `.cursor/bin`.
|
|
42
|
+
return CURSOR_SANDBOX_BIN_DIRS.flatMap((relativeDir) => basenames.map((basename) => path.posix.join(homeDir, relativeDir, basename)));
|
|
43
|
+
}
|
|
44
|
+
function candidateSandboxPathEntries(homeDir) {
|
|
45
|
+
return CURSOR_SANDBOX_BIN_DIRS.map((relativeDir) => path.posix.join(homeDir, relativeDir));
|
|
46
|
+
}
|
|
47
|
+
function readMarkedValue(lines, marker) {
|
|
48
|
+
const matchedLine = lines.find((line) => line.startsWith(marker));
|
|
49
|
+
if (!matchedLine)
|
|
50
|
+
return null;
|
|
51
|
+
const value = matchedLine.slice(marker.length).trim();
|
|
52
|
+
return value.length > 0 ? value : null;
|
|
53
|
+
}
|
|
54
|
+
async function readSandboxCursorRuntimeInfo(input) {
|
|
55
|
+
const preferredBasenames = !hasPathSeparator(input.command)
|
|
56
|
+
? preferredSandboxCommandBasenames(input.command)
|
|
57
|
+
: [];
|
|
58
|
+
const hintedRemoteSystemHomeDir = input.remoteSystemHomeDirHint?.trim() || null;
|
|
59
|
+
const homeMarker = "__PAPERCLIP_CURSOR_HOME__:";
|
|
60
|
+
const preferredMarker = "__PAPERCLIP_CURSOR_AGENT__:";
|
|
61
|
+
try {
|
|
62
|
+
// When the caller has already resolved the remote `$HOME`, probe absolute
|
|
63
|
+
// paths so the shell doesn't depend on its own environment to interpret
|
|
64
|
+
// `$HOME`. Without a hint we still probe `$HOME/...` literally — this is
|
|
65
|
+
// how the sandbox finds a user-prefixed install before falling back to a
|
|
66
|
+
// PATH lookup. Skipping the `$HOME` probes here was the regression behind
|
|
67
|
+
// server tests `cursor-local-adapter-environment.test.ts` and
|
|
68
|
+
// `cursor-local-execute.test.ts` failing on a host whose own `agent`
|
|
69
|
+
// command resolves via PATH.
|
|
70
|
+
const fixedCandidatePaths = preferredBasenames.length > 0
|
|
71
|
+
? hintedRemoteSystemHomeDir
|
|
72
|
+
? candidateSandboxCommandPaths(hintedRemoteSystemHomeDir, preferredBasenames)
|
|
73
|
+
: preferredBasenames.flatMap((basename) => CURSOR_SANDBOX_BIN_DIRS.map((relativeDir) => `$HOME/${relativeDir}/${basename}`))
|
|
74
|
+
: [];
|
|
75
|
+
const preferredProbeBranches = [
|
|
76
|
+
...fixedCandidatePaths.map((fixedPath) => `[ -x ${JSON.stringify(fixedPath)} ] && printf ${JSON.stringify(`${preferredMarker}%s\\n`)} ${JSON.stringify(fixedPath)}`),
|
|
77
|
+
...preferredBasenames.map((basename) => `resolved="$(command -v ${JSON.stringify(basename)} 2>/dev/null)" && [ -n "$resolved" ] && printf ${JSON.stringify(`${preferredMarker}%s\\n`)} "$resolved"`),
|
|
78
|
+
];
|
|
79
|
+
const result = await runAdapterExecutionTargetShellCommand(input.runId, input.target, [
|
|
80
|
+
hintedRemoteSystemHomeDir
|
|
81
|
+
? `printf ${JSON.stringify(`${homeMarker}%s\\n`)} ${JSON.stringify(hintedRemoteSystemHomeDir)}`
|
|
82
|
+
: `printf ${JSON.stringify(`${homeMarker}%s\\n`)} "$HOME"`,
|
|
83
|
+
preferredProbeBranches.length > 0
|
|
84
|
+
? preferredProbeBranches
|
|
85
|
+
.map((probeBranch, index) => {
|
|
86
|
+
const branchKeyword = index === 0 ? "if" : "elif";
|
|
87
|
+
return `${branchKeyword} ${probeBranch}; then :`;
|
|
88
|
+
})
|
|
89
|
+
.join("; ") + "; fi; :"
|
|
90
|
+
: "",
|
|
91
|
+
].filter(Boolean).join("; "), {
|
|
92
|
+
cwd: input.cwd,
|
|
93
|
+
env: input.env,
|
|
94
|
+
timeoutSec: input.timeoutSec,
|
|
95
|
+
graceSec: input.graceSec,
|
|
96
|
+
});
|
|
97
|
+
if (result.timedOut || (result.exitCode ?? 1) !== 0) {
|
|
98
|
+
return {
|
|
99
|
+
remoteSystemHomeDir: null,
|
|
100
|
+
preferredCommandPath: null,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const lines = result.stdout.split(/\r?\n/);
|
|
104
|
+
return {
|
|
105
|
+
remoteSystemHomeDir: readMarkedValue(lines, homeMarker),
|
|
106
|
+
preferredCommandPath: readMarkedValue(lines, preferredMarker),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return {
|
|
111
|
+
remoteSystemHomeDir: null,
|
|
112
|
+
preferredCommandPath: null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function isDefaultCursorCommand(command) {
|
|
117
|
+
return DEFAULT_CURSOR_COMMAND_BASENAMES.has(commandBasename(command));
|
|
118
|
+
}
|
|
119
|
+
export async function prepareCursorSandboxCommand(input) {
|
|
120
|
+
if (input.target?.kind !== "remote" || input.target.transport !== "sandbox") {
|
|
121
|
+
return {
|
|
122
|
+
command: input.command,
|
|
123
|
+
env: input.env,
|
|
124
|
+
remoteSystemHomeDir: null,
|
|
125
|
+
addedPathEntry: null,
|
|
126
|
+
preferredCommandPath: null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const runtimeInfo = await readSandboxCursorRuntimeInfo({
|
|
130
|
+
runId: input.runId,
|
|
131
|
+
target: input.target,
|
|
132
|
+
command: input.command,
|
|
133
|
+
cwd: input.cwd,
|
|
134
|
+
env: input.env,
|
|
135
|
+
remoteSystemHomeDirHint: input.remoteSystemHomeDirHint,
|
|
136
|
+
timeoutSec: input.timeoutSec,
|
|
137
|
+
graceSec: input.graceSec,
|
|
138
|
+
});
|
|
139
|
+
const remoteSystemHomeDir = runtimeInfo.remoteSystemHomeDir ?? input.remoteSystemHomeDirHint?.trim() ?? null;
|
|
140
|
+
if (!remoteSystemHomeDir) {
|
|
141
|
+
return {
|
|
142
|
+
command: input.command,
|
|
143
|
+
env: input.env,
|
|
144
|
+
remoteSystemHomeDir: null,
|
|
145
|
+
addedPathEntry: null,
|
|
146
|
+
preferredCommandPath: null,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const sandboxPathEntries = candidateSandboxPathEntries(remoteSystemHomeDir);
|
|
150
|
+
const runtimeEnv = ensurePathInEnv(input.env);
|
|
151
|
+
const currentPath = runtimeEnv.PATH ?? runtimeEnv.Path ?? "";
|
|
152
|
+
const nextPath = prependPosixPathEntries(currentPath, sandboxPathEntries);
|
|
153
|
+
const env = nextPath === currentPath ? input.env : { ...input.env, PATH: nextPath };
|
|
154
|
+
const addedPathEntry = nextPath === currentPath ? null : sandboxPathEntries[0];
|
|
155
|
+
if (!runtimeInfo.preferredCommandPath) {
|
|
156
|
+
return {
|
|
157
|
+
command: input.command,
|
|
158
|
+
env,
|
|
159
|
+
remoteSystemHomeDir,
|
|
160
|
+
addedPathEntry,
|
|
161
|
+
preferredCommandPath: null,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
command: runtimeInfo.preferredCommandPath,
|
|
166
|
+
env,
|
|
167
|
+
remoteSystemHomeDir,
|
|
168
|
+
addedPathEntry,
|
|
169
|
+
preferredCommandPath: runtimeInfo.preferredCommandPath,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=remote-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-command.js","sourceRoot":"","sources":["../../src/server/remote-command.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,qCAAqC,GAEtC,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,sDAAsD,CAAC;AAEvF,MAAM,gCAAgC,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,8EAA8E;AAC9E,WAAW;AACX,MAAM,uBAAuB,GAAG;IAC9B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;IAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC;CAClC,CAAC;AAEF,SAAS,eAAe,CAAC,OAAe;IACtC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB,EAAE,KAAa;IAC7D,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC;AAED,SAAS,uBAAuB,CAAC,SAAiB,EAAE,OAAiB;IACnE,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,gCAAgC,CAAC,OAAe;IACvD,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,gCAAgC,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/D,OAAO,QAAQ,KAAK,cAAc;QAChC,CAAC,CAAC,CAAC,cAAc,EAAE,OAAO,CAAC;QAC3B,CAAC,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,4BAA4B,CAAC,OAAe,EAAE,SAAmB;IACxE,mEAAmE;IACnE,gEAAgE;IAChE,oEAAoE;IACpE,oCAAoC;IACpC,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CACrD,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAAC,OAAe;IAClD,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;AAC7F,CAAC;AAOD,SAAS,eAAe,CAAC,KAAe,EAAE,MAAc;IACtD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,KAAK,UAAU,4BAA4B,CAAC,KAS3C;IACC,MAAM,kBAAkB,GACtB,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC;QAC9B,CAAC,CAAC,gCAAgC,CAAC,KAAK,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,yBAAyB,GAAG,KAAK,CAAC,uBAAuB,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAChF,MAAM,UAAU,GAAG,4BAA4B,CAAC;IAChD,MAAM,eAAe,GAAG,6BAA6B,CAAC;IACtD,IAAI,CAAC;QACH,0EAA0E;QAC1E,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,0EAA0E;QAC1E,8DAA8D;QAC9D,qEAAqE;QACrE,6BAA6B;QAC7B,MAAM,mBAAmB,GACvB,kBAAkB,CAAC,MAAM,GAAG,CAAC;YAC3B,CAAC,CAAC,yBAAyB;gBACzB,CAAC,CAAC,4BAA4B,CAAC,yBAAyB,EAAE,kBAAkB,CAAC;gBAC7E,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CACtC,uBAAuB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAC1C,SAAS,WAAW,IAAI,QAAQ,EAAE,CACnC,CACF;YACL,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,sBAAsB,GAAG;YAC7B,GAAG,mBAAmB,CAAC,GAAG,CACxB,CAAC,SAAS,EAAE,EAAE,CACZ,QAAQ,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,gBAAgB,IAAI,CAAC,SAAS,CAAC,GAAG,eAAe,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAC5H;YACD,GAAG,kBAAkB,CAAC,GAAG,CACvB,CAAC,QAAQ,EAAE,EAAE,CACX,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,kDAAkD,IAAI,CAAC,SAAS,CAAC,GAAG,eAAe,OAAO,CAAC,cAAc,CAC9J;SACF,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,qCAAqC,CACxD,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,MAAM,EACZ;YACE,yBAAyB;gBACvB,CAAC,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,UAAU,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC,EAAE;gBAC/F,CAAC,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,UAAU,OAAO,CAAC,UAAU;YAC5D,sBAAsB,CAAC,MAAM,GAAG,CAAC;gBAC/B,CAAC,CAAC,sBAAsB;qBACrB,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE;oBAC1B,MAAM,aAAa,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;oBAClD,OAAO,GAAG,aAAa,IAAI,WAAW,UAAU,CAAC;gBACnD,CAAC,CAAC;qBACD,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS;gBACzB,CAAC,CAAC,EAAE;SACP,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B;YACE,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CACF,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO;gBACL,mBAAmB,EAAE,IAAI;gBACzB,oBAAoB,EAAE,IAAI;aAC3B,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,OAAO;YACL,mBAAmB,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC;YACvD,oBAAoB,EAAE,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC;SAC9D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,mBAAmB,EAAE,IAAI;YACzB,oBAAoB,EAAE,IAAI;SAC3B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,gCAAgC,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;AACxE,CAAC;AAUD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KASjD;IACC,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5E,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,mBAAmB,EAAE,IAAI;YACzB,cAAc,EAAE,IAAI;YACpB,oBAAoB,EAAE,IAAI;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,4BAA4B,CAAC;QACrD,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;QACtD,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC;IACH,MAAM,mBAAmB,GACvB,WAAW,CAAC,mBAAmB,IAAI,KAAK,CAAC,uBAAuB,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAEnF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,mBAAmB,EAAE,IAAI;YACzB,cAAc,EAAE,IAAI;YACpB,oBAAoB,EAAE,IAAI;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,kBAAkB,GAAG,2BAA2B,CAAC,mBAAmB,CAAC,CAAC;IAC5E,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC;IAC7D,MAAM,QAAQ,GAAG,uBAAuB,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACpF,MAAM,cAAc,GAAG,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAE/E,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACtC,OAAO;YACL,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG;YACH,mBAAmB;YACnB,cAAc;YACd,oBAAoB,EAAE,IAAI;SAC3B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,WAAW,CAAC,oBAAoB;QACzC,GAAG;QACH,mBAAmB;QACnB,cAAc;QACd,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;KACvD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-command.test.d.ts","sourceRoot":"","sources":["../../src/server/remote-command.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { runChildProcess } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
|
|
6
|
+
import { prepareCursorSandboxCommand } from "./remote-command.js";
|
|
7
|
+
function createLocalSandboxRunner() {
|
|
8
|
+
let counter = 0;
|
|
9
|
+
return {
|
|
10
|
+
execute: async (input) => {
|
|
11
|
+
counter += 1;
|
|
12
|
+
return await runChildProcess(`cursor-remote-command-${counter}`, input.command, input.args ?? [], {
|
|
13
|
+
cwd: input.cwd ?? process.cwd(),
|
|
14
|
+
env: input.env ?? {},
|
|
15
|
+
stdin: input.stdin,
|
|
16
|
+
timeoutSec: Math.max(1, Math.ceil((input.timeoutMs ?? 30_000) / 1000)),
|
|
17
|
+
graceSec: 5,
|
|
18
|
+
onLog: input.onLog ?? (async () => { }),
|
|
19
|
+
onSpawn: input.onSpawn
|
|
20
|
+
? async (meta) => input.onSpawn?.({ pid: meta.pid, startedAt: meta.startedAt })
|
|
21
|
+
: undefined,
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function writeFakeAgent(commandPath) {
|
|
27
|
+
const script = `#!/bin/sh
|
|
28
|
+
printf '%s\\n' ok
|
|
29
|
+
`;
|
|
30
|
+
await fs.mkdir(path.dirname(commandPath), { recursive: true });
|
|
31
|
+
await fs.writeFile(commandPath, script, "utf8");
|
|
32
|
+
await fs.chmod(commandPath, 0o755);
|
|
33
|
+
}
|
|
34
|
+
describe("prepareCursorSandboxCommand", () => {
|
|
35
|
+
it("prefers the Cursor installer bin directory when the default agent entrypoint is installed there", async () => {
|
|
36
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-cursor-remote-command-cursor-bin-"));
|
|
37
|
+
const systemHomeDir = path.join(root, "system-home");
|
|
38
|
+
const managedHomeDir = path.join(root, "managed-home");
|
|
39
|
+
const remoteWorkspace = path.join(root, "workspace");
|
|
40
|
+
const cursorAgentPath = path.join(systemHomeDir, ".cursor", "bin", "agent");
|
|
41
|
+
await fs.mkdir(remoteWorkspace, { recursive: true });
|
|
42
|
+
await writeFakeAgent(cursorAgentPath);
|
|
43
|
+
try {
|
|
44
|
+
const result = await prepareCursorSandboxCommand({
|
|
45
|
+
runId: "run-remote-command-cursor-bin",
|
|
46
|
+
target: {
|
|
47
|
+
kind: "remote",
|
|
48
|
+
transport: "sandbox",
|
|
49
|
+
shellCommand: "bash",
|
|
50
|
+
remoteCwd: remoteWorkspace,
|
|
51
|
+
runner: createLocalSandboxRunner(),
|
|
52
|
+
timeoutMs: 30_000,
|
|
53
|
+
},
|
|
54
|
+
command: "agent",
|
|
55
|
+
cwd: remoteWorkspace,
|
|
56
|
+
env: {
|
|
57
|
+
HOME: managedHomeDir,
|
|
58
|
+
PATH: "/usr/bin:/bin",
|
|
59
|
+
},
|
|
60
|
+
remoteSystemHomeDirHint: systemHomeDir,
|
|
61
|
+
timeoutSec: 30,
|
|
62
|
+
graceSec: 5,
|
|
63
|
+
});
|
|
64
|
+
expect(result.command).toBe(cursorAgentPath);
|
|
65
|
+
expect(result.preferredCommandPath).toBe(cursorAgentPath);
|
|
66
|
+
expect(result.remoteSystemHomeDir).toBe(systemHomeDir);
|
|
67
|
+
expect(result.addedPathEntry).toBe(path.join(systemHomeDir, ".local", "bin"));
|
|
68
|
+
expect(result.env.PATH?.split(":").slice(0, 2)).toEqual([
|
|
69
|
+
path.join(systemHomeDir, ".local", "bin"),
|
|
70
|
+
path.join(systemHomeDir, ".cursor", "bin"),
|
|
71
|
+
]);
|
|
72
|
+
expect(result.env.PATH).not.toContain(path.join(managedHomeDir, ".cursor", "bin"));
|
|
73
|
+
expect(result.env.PATH).not.toContain(path.join(managedHomeDir, ".local", "bin"));
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
it("keeps probing the original sandbox home after managed HOME overrides", async () => {
|
|
80
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-cursor-remote-command-"));
|
|
81
|
+
const systemHomeDir = path.join(root, "system-home");
|
|
82
|
+
const managedHomeDir = path.join(root, "managed-home");
|
|
83
|
+
const remoteWorkspace = path.join(root, "workspace");
|
|
84
|
+
const systemAgentPath = path.join(systemHomeDir, ".local", "bin", "agent");
|
|
85
|
+
await fs.mkdir(remoteWorkspace, { recursive: true });
|
|
86
|
+
await writeFakeAgent(systemAgentPath);
|
|
87
|
+
try {
|
|
88
|
+
const result = await prepareCursorSandboxCommand({
|
|
89
|
+
runId: "run-remote-command-1",
|
|
90
|
+
target: {
|
|
91
|
+
kind: "remote",
|
|
92
|
+
transport: "sandbox",
|
|
93
|
+
shellCommand: "bash",
|
|
94
|
+
remoteCwd: remoteWorkspace,
|
|
95
|
+
runner: createLocalSandboxRunner(),
|
|
96
|
+
timeoutMs: 30_000,
|
|
97
|
+
},
|
|
98
|
+
command: "agent",
|
|
99
|
+
cwd: remoteWorkspace,
|
|
100
|
+
env: {
|
|
101
|
+
HOME: managedHomeDir,
|
|
102
|
+
PATH: "/usr/bin:/bin",
|
|
103
|
+
},
|
|
104
|
+
remoteSystemHomeDirHint: systemHomeDir,
|
|
105
|
+
timeoutSec: 30,
|
|
106
|
+
graceSec: 5,
|
|
107
|
+
});
|
|
108
|
+
expect(result.command).toBe(systemAgentPath);
|
|
109
|
+
expect(result.preferredCommandPath).toBe(systemAgentPath);
|
|
110
|
+
expect(result.remoteSystemHomeDir).toBe(systemHomeDir);
|
|
111
|
+
expect(result.addedPathEntry).toBe(path.join(systemHomeDir, ".local", "bin"));
|
|
112
|
+
expect(result.env.PATH?.split(":").slice(0, 2)).toEqual([
|
|
113
|
+
path.join(systemHomeDir, ".local", "bin"),
|
|
114
|
+
path.join(systemHomeDir, ".cursor", "bin"),
|
|
115
|
+
]);
|
|
116
|
+
expect(result.env.PATH).not.toContain(path.join(managedHomeDir, ".local", "bin"));
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=remote-command.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-command.test.js","sourceRoot":"","sources":["../../src/server/remote-command.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AdapterSkillContext, AdapterSkillSnapshot } from "@tickernelz/paperclip-pro-adapter-utils";
|
|
2
|
+
export declare function resolveCursorSkillsHome(config: Record<string, unknown>): string;
|
|
3
|
+
export declare function listCursorSkills(ctx: AdapterSkillContext): Promise<AdapterSkillSnapshot>;
|
|
4
|
+
export declare function syncCursorSkills(ctx: AdapterSkillContext, desiredSkills: string[]): Promise<AdapterSkillSnapshot>;
|
|
5
|
+
export declare function resolveCursorDesiredSkillNames(config: Record<string, unknown>, availableEntries: Array<{
|
|
6
|
+
key: string;
|
|
7
|
+
}>): string[];
|
|
8
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,yCAAyC,CAAC;AAejD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,UAQtE;AAoBD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAE9F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,mBAAmB,EACxB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,YAGzC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { buildPersistentSkillSnapshot, ensurePaperclipSkillSymlink, readPaperclipRuntimeSkillEntries, readInstalledSkillTargets, resolveLegacyPaperclipDesiredSkillNames, } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
|
|
6
|
+
const __moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
function asString(value) {
|
|
8
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
9
|
+
}
|
|
10
|
+
export function resolveCursorSkillsHome(config) {
|
|
11
|
+
const env = typeof config.env === "object" && config.env !== null && !Array.isArray(config.env)
|
|
12
|
+
? config.env
|
|
13
|
+
: {};
|
|
14
|
+
const configuredHome = asString(env.HOME);
|
|
15
|
+
const home = configuredHome ? path.resolve(configuredHome) : os.homedir();
|
|
16
|
+
return path.join(home, ".cursor", "skills");
|
|
17
|
+
}
|
|
18
|
+
async function buildCursorSkillSnapshot(config) {
|
|
19
|
+
const availableEntries = await readPaperclipRuntimeSkillEntries(config, __moduleDir);
|
|
20
|
+
const desiredSkills = resolveLegacyPaperclipDesiredSkillNames(config, availableEntries);
|
|
21
|
+
const skillsHome = resolveCursorSkillsHome(config);
|
|
22
|
+
const installed = await readInstalledSkillTargets(skillsHome);
|
|
23
|
+
return buildPersistentSkillSnapshot({
|
|
24
|
+
adapterType: "cursor",
|
|
25
|
+
availableEntries,
|
|
26
|
+
desiredSkills,
|
|
27
|
+
installed,
|
|
28
|
+
skillsHome,
|
|
29
|
+
locationLabel: "~/.cursor/skills",
|
|
30
|
+
missingDetail: "Configured but not currently linked into the Cursor skills home.",
|
|
31
|
+
externalConflictDetail: "Skill name is occupied by an external installation.",
|
|
32
|
+
externalDetail: "Installed outside Paperclip management.",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function listCursorSkills(ctx) {
|
|
36
|
+
return buildCursorSkillSnapshot(ctx.config);
|
|
37
|
+
}
|
|
38
|
+
export async function syncCursorSkills(ctx, desiredSkills) {
|
|
39
|
+
const availableEntries = await readPaperclipRuntimeSkillEntries(ctx.config, __moduleDir);
|
|
40
|
+
const desiredSet = new Set([
|
|
41
|
+
...resolveLegacyPaperclipDesiredSkillNames({}, availableEntries),
|
|
42
|
+
...desiredSkills,
|
|
43
|
+
]);
|
|
44
|
+
const skillsHome = resolveCursorSkillsHome(ctx.config);
|
|
45
|
+
await fs.mkdir(skillsHome, { recursive: true });
|
|
46
|
+
const installed = await readInstalledSkillTargets(skillsHome);
|
|
47
|
+
const availableByRuntimeName = new Map(availableEntries.map((entry) => [entry.runtimeName, entry]));
|
|
48
|
+
for (const available of availableEntries) {
|
|
49
|
+
if (!desiredSet.has(available.key))
|
|
50
|
+
continue;
|
|
51
|
+
const target = path.join(skillsHome, available.runtimeName);
|
|
52
|
+
await ensurePaperclipSkillSymlink(available.source, target);
|
|
53
|
+
}
|
|
54
|
+
for (const [name, installedEntry] of installed.entries()) {
|
|
55
|
+
const available = availableByRuntimeName.get(name);
|
|
56
|
+
if (!available)
|
|
57
|
+
continue;
|
|
58
|
+
if (desiredSet.has(available.key))
|
|
59
|
+
continue;
|
|
60
|
+
if (installedEntry.targetPath !== available.source)
|
|
61
|
+
continue;
|
|
62
|
+
await fs.unlink(path.join(skillsHome, name)).catch(() => { });
|
|
63
|
+
}
|
|
64
|
+
return buildCursorSkillSnapshot(ctx.config);
|
|
65
|
+
}
|
|
66
|
+
export function resolveCursorDesiredSkillNames(config, availableEntries) {
|
|
67
|
+
return resolveLegacyPaperclipDesiredSkillNames(config, availableEntries);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKzC,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,gCAAgC,EAChC,yBAAyB,EACzB,uCAAuC,GACxC,MAAM,sDAAsD,CAAC;AAE9D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEjE,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAA+B;IACrE,MAAM,GAAG,GACP,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;QACjF,CAAC,CAAE,MAAM,CAAC,GAA+B;QACzC,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,cAAc,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;IAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,wBAAwB,CAAC,MAA+B;IACrE,MAAM,gBAAgB,GAAG,MAAM,gCAAgC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrF,MAAM,aAAa,GAAG,uCAAuC,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACxF,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,MAAM,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAC9D,OAAO,4BAA4B,CAAC;QAClC,WAAW,EAAE,QAAQ;QACrB,gBAAgB;QAChB,aAAa;QACb,SAAS;QACT,UAAU;QACV,aAAa,EAAE,kBAAkB;QACjC,aAAa,EAAE,kEAAkE;QACjF,sBAAsB,EAAE,qDAAqD;QAC7E,cAAc,EAAE,yCAAyC;KAC1D,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAwB;IAC7D,OAAO,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAwB,EACxB,aAAuB;IAEvB,MAAM,gBAAgB,GAAG,MAAM,gCAAgC,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;QACzB,GAAG,uCAAuC,CAAC,EAAE,EAAE,gBAAgB,CAAC;QAChE,GAAG,aAAa;KACjB,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,uBAAuB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,MAAM,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAEpG,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;QACzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,SAAS;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QAC5D,MAAM,2BAA2B,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QACzD,MAAM,SAAS,GAAG,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,IAAI,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5C,IAAI,cAAc,CAAC,UAAU,KAAK,SAAS,CAAC,MAAM;YAAE,SAAS;QAC7D,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,MAA+B,EAC/B,gBAAwC;IAExC,OAAO,uCAAuC,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AdapterEnvironmentTestContext, AdapterEnvironmentTestResult } from "@tickernelz/paperclip-pro-adapter-utils";
|
|
2
|
+
export interface CursorAuthInfo {
|
|
3
|
+
email: string | null;
|
|
4
|
+
displayName: string | null;
|
|
5
|
+
userId: number | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function cursorConfigPath(cursorHome?: string): string;
|
|
8
|
+
export declare function readCursorAuthInfo(cursorHome?: string): Promise<CursorAuthInfo | null>;
|
|
9
|
+
export declare function testEnvironment(ctx: AdapterEnvironmentTestContext): Promise<AdapterEnvironmentTestResult>;
|
|
10
|
+
//# sourceMappingURL=test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/server/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,6BAA6B,EAC7B,4BAA4B,EAC7B,MAAM,yCAAyC,CAAC;AAmDjD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAsB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAuB5F;AAKD,wBAAsB,eAAe,CACnC,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA0RvC"}
|