qiksy 1.0.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/ARCHITECTURE.md +78 -0
- package/INSTALL-PROMPT.md +53 -0
- package/bin/qiksy.mjs +302 -0
- package/package.json +32 -0
- package/tools/client-finder/vendor/README.md +70 -0
- package/tools/client-finder/vendor/find.mjs +121 -0
- package/tools/client-finder/vendor/icp/assist-pl-shops.json +30 -0
- package/tools/client-finder/vendor/icp/assist-ua-shops.json +30 -0
- package/tools/client-finder/vendor/knowledge/assist.md +68 -0
- package/tools/client-finder/vendor/knowledge/custom.md +36 -0
- package/tools/client-finder/vendor/knowledge/multilogin.md +29 -0
- package/tools/client-finder/vendor/knowledge/pay.md +26 -0
- package/tools/client-finder/vendor/knowledge/qa-copilot.md +43 -0
- package/tools/client-finder/vendor/knowledge/travel.md +43 -0
- package/tools/client-finder/vendor/knowledge/work-finder.md +52 -0
- package/tools/client-finder/vendor/lib/access.mjs +108 -0
- package/tools/client-finder/vendor/lib/agent.mjs +204 -0
- package/tools/client-finder/vendor/lib/approver-mcp.mjs +78 -0
- package/tools/client-finder/vendor/lib/browser.mjs +108 -0
- package/tools/client-finder/vendor/lib/catalog.mjs +86 -0
- package/tools/client-finder/vendor/lib/channels.mjs +54 -0
- package/tools/client-finder/vendor/lib/deliver.mjs +89 -0
- package/tools/client-finder/vendor/lib/engine.mjs +283 -0
- package/tools/client-finder/vendor/lib/formats.mjs +108 -0
- package/tools/client-finder/vendor/lib/jobs.mjs +75 -0
- package/tools/client-finder/vendor/lib/knowledge.mjs +26 -0
- package/tools/client-finder/vendor/lib/prompts.mjs +183 -0
- package/tools/client-finder/vendor/lib/report.mjs +75 -0
- package/tools/client-finder/vendor/lib/scope.mjs +162 -0
- package/tools/client-finder/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/client-finder/vendor/lib/verify.mjs +96 -0
- package/tools/client-finder/vendor/package.json +8 -0
- package/tools/client-finder/vendor/server.mjs +390 -0
- package/tools/travel/vendor/README.md +58 -0
- package/tools/travel/vendor/docs/CONTRACT.md +174 -0
- package/tools/travel/vendor/docs/ENGINE-MIGRATION.md +33 -0
- package/tools/travel/vendor/lib/agent.mjs +190 -0
- package/tools/travel/vendor/lib/engine.mjs +283 -0
- package/tools/travel/vendor/lib/jobs.mjs +125 -0
- package/tools/travel/vendor/lib/license.mjs +41 -0
- package/tools/travel/vendor/lib/plans.mjs +28 -0
- package/tools/travel/vendor/lib/prompts.mjs +394 -0
- package/tools/travel/vendor/lib/proposal.mjs +207 -0
- package/tools/travel/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/travel/vendor/lib/store.mjs +75 -0
- package/tools/travel/vendor/package.json +12 -0
- package/tools/travel/vendor/public/app.js +996 -0
- package/tools/travel/vendor/public/index.html +112 -0
- package/tools/travel/vendor/public/styles.css +760 -0
- package/tools/travel/vendor/scripts/approver-mcp.mjs +80 -0
- package/tools/travel/vendor/scripts/launch-browser.mjs +77 -0
- package/tools/travel/vendor/server.mjs +755 -0
- package/tools/work-finder/vendor/.claude/settings.local.json +27 -0
- package/tools/work-finder/vendor/.mcp.json +9 -0
- package/tools/work-finder/vendor/CLAUDE.md +24 -0
- package/tools/work-finder/vendor/README.md +44 -0
- package/tools/work-finder/vendor/bin/qiksy-work-finder.mjs +127 -0
- package/tools/work-finder/vendor/lib/agent.mjs +159 -0
- package/tools/work-finder/vendor/lib/catalog.mjs +41 -0
- package/tools/work-finder/vendor/lib/channels.mjs +73 -0
- package/tools/work-finder/vendor/lib/engine.mjs +283 -0
- package/tools/work-finder/vendor/lib/jobs.mjs +127 -0
- package/tools/work-finder/vendor/lib/license.mjs +60 -0
- package/tools/work-finder/vendor/lib/linkcheck.mjs +72 -0
- package/tools/work-finder/vendor/lib/linkedin.mjs +22 -0
- package/tools/work-finder/vendor/lib/plans.mjs +33 -0
- package/tools/work-finder/vendor/lib/prompts.mjs +217 -0
- package/tools/work-finder/vendor/lib/spawn-claude.mjs +44 -0
- package/tools/work-finder/vendor/lib/store.mjs +125 -0
- package/tools/work-finder/vendor/package.json +41 -0
- package/tools/work-finder/vendor/public/app.js +1863 -0
- package/tools/work-finder/vendor/public/index.html +518 -0
- package/tools/work-finder/vendor/public/styles.css +930 -0
- package/tools/work-finder/vendor/scripts/approver-mcp.mjs +69 -0
- package/tools/work-finder/vendor/scripts/extract-linkedin.mjs +81 -0
- package/tools/work-finder/vendor/scripts/launch-browser.mjs +78 -0
- package/tools/work-finder/vendor/scripts/screenshot.mjs +17 -0
- package/tools/work-finder/vendor/server.mjs +1006 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Minimal MCP stdio server: permission-prompt handler for headless agents.
|
|
4
|
+
*
|
|
5
|
+
* The user's global ~/.claude/settings.json puts WebSearch/WebFetch in the
|
|
6
|
+
* "ask" list; in -p mode "ask" becomes "deny". This server is passed via
|
|
7
|
+
* `--permission-prompt-tool mcp__approver__approve` and auto-approves only
|
|
8
|
+
* the whitelisted tools below — everything else stays denied.
|
|
9
|
+
*/
|
|
10
|
+
const ALLOW = [/^WebSearch$/, /^WebFetch$/, /^ToolSearch$/, /^mcp__playwright__/];
|
|
11
|
+
|
|
12
|
+
const send = msg => process.stdout.write(JSON.stringify(msg) + '\n');
|
|
13
|
+
|
|
14
|
+
function handle(msg) {
|
|
15
|
+
const { id, method, params } = msg;
|
|
16
|
+
if (method === 'initialize') {
|
|
17
|
+
return send({
|
|
18
|
+
jsonrpc: '2.0', id,
|
|
19
|
+
result: {
|
|
20
|
+
protocolVersion: params?.protocolVersion || '2024-11-05',
|
|
21
|
+
capabilities: { tools: {} },
|
|
22
|
+
serverInfo: { name: 'approver', version: '1.0.0' },
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (method === 'tools/list') {
|
|
27
|
+
return send({
|
|
28
|
+
jsonrpc: '2.0', id,
|
|
29
|
+
result: {
|
|
30
|
+
tools: [{
|
|
31
|
+
name: 'approve',
|
|
32
|
+
description: 'Auto-approve permission prompts for whitelisted tools',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
tool_name: { type: 'string' },
|
|
37
|
+
input: { type: 'object' },
|
|
38
|
+
tool_use_id: { type: 'string' },
|
|
39
|
+
},
|
|
40
|
+
required: ['tool_name', 'input'],
|
|
41
|
+
},
|
|
42
|
+
}],
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (method === 'tools/call') {
|
|
47
|
+
const { name, arguments: args = {} } = params || {};
|
|
48
|
+
if (name !== 'approve') return send({ jsonrpc: '2.0', id, error: { code: -32601, message: 'unknown tool' } });
|
|
49
|
+
const ok = ALLOW.some(re => re.test(args.tool_name || ''));
|
|
50
|
+
const payload = ok
|
|
51
|
+
? { behavior: 'allow', updatedInput: args.input || {} }
|
|
52
|
+
: { behavior: 'deny', message: `tool ${args.tool_name} is not whitelisted for work-finder agents` };
|
|
53
|
+
return send({ jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: JSON.stringify(payload) }] } });
|
|
54
|
+
}
|
|
55
|
+
if (id !== undefined) send({ jsonrpc: '2.0', id, result: {} });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let buf = '';
|
|
59
|
+
process.stdin.setEncoding('utf8');
|
|
60
|
+
process.stdin.on('data', chunk => {
|
|
61
|
+
buf += chunk;
|
|
62
|
+
let nl;
|
|
63
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
64
|
+
const line = buf.slice(0, nl).trim();
|
|
65
|
+
buf = buf.slice(nl + 1);
|
|
66
|
+
if (!line) continue;
|
|
67
|
+
try { handle(JSON.parse(line)); } catch { /* ignore malformed line */ }
|
|
68
|
+
}
|
|
69
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Extract a LinkedIn profile (own resume) via the CDP browser on :9222.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node scripts/extract-linkedin.mjs <profile-url> <output.txt>
|
|
7
|
+
*
|
|
8
|
+
* Opens NEW tabs in the already-running (logged-in) Chrome, reads the
|
|
9
|
+
* profile page + detail subpages, dumps raw visible text to <output.txt>.
|
|
10
|
+
* The user's own tabs are left untouched; new tabs are closed afterwards.
|
|
11
|
+
*
|
|
12
|
+
* Requires playwright-core; resolved from iucn-mono's node_modules to avoid
|
|
13
|
+
* an install here (override with PLAYWRIGHT_CORE env var).
|
|
14
|
+
*/
|
|
15
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
16
|
+
import { dirname } from 'node:path';
|
|
17
|
+
|
|
18
|
+
const PW = process.env.PLAYWRIGHT_CORE
|
|
19
|
+
|| '/Users/dimalesnak/Desktop/www/iucn-mono/node_modules/playwright-core/index.mjs';
|
|
20
|
+
const { chromium } = await import(PW);
|
|
21
|
+
|
|
22
|
+
const CDP = process.env.CDP_ENDPOINT || 'http://localhost:9222';
|
|
23
|
+
const profileUrl = process.argv[2];
|
|
24
|
+
const outFile = process.argv[3];
|
|
25
|
+
if (!profileUrl || !outFile) {
|
|
26
|
+
console.error('Usage: node scripts/extract-linkedin.mjs <profile-url> <output.txt>');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const SUBPAGES = ['experience', 'education', 'skills', 'certifications', 'languages', 'projects'];
|
|
31
|
+
|
|
32
|
+
const browser = await chromium.connectOverCDP(CDP);
|
|
33
|
+
const context = browser.contexts()[0];
|
|
34
|
+
if (!context) {
|
|
35
|
+
console.error('No browser context found on CDP endpoint.');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function readPage(url) {
|
|
40
|
+
const page = await context.newPage();
|
|
41
|
+
try {
|
|
42
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
|
|
43
|
+
await page.waitForSelector('main', { timeout: 15_000 });
|
|
44
|
+
// LinkedIn lazy-loads sections on scroll — walk down the page.
|
|
45
|
+
await page.evaluate(async () => {
|
|
46
|
+
await new Promise(resolve => {
|
|
47
|
+
let last = -1;
|
|
48
|
+
const step = () => {
|
|
49
|
+
window.scrollBy(0, 700);
|
|
50
|
+
const y = window.scrollY;
|
|
51
|
+
if (y === last) return resolve();
|
|
52
|
+
last = y;
|
|
53
|
+
setTimeout(step, 250);
|
|
54
|
+
};
|
|
55
|
+
step();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => {});
|
|
59
|
+
return await page.evaluate(() => document.querySelector('main')?.innerText || '');
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return `[extract error: ${e.message.split('\n')[0]}]`;
|
|
62
|
+
} finally {
|
|
63
|
+
await page.close().catch(() => {});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const base = profileUrl.replace(/\?.*$/, '').replace(/\/$/, '');
|
|
68
|
+
let out = `SOURCE: ${base}\n\n===== MAIN PROFILE =====\n\n`;
|
|
69
|
+
console.error('reading main profile…');
|
|
70
|
+
out += await readPage(base + '/');
|
|
71
|
+
|
|
72
|
+
for (const sub of SUBPAGES) {
|
|
73
|
+
console.error(`reading details/${sub}…`);
|
|
74
|
+
const text = await readPage(`${base}/details/${sub}/`);
|
|
75
|
+
out += `\n\n===== DETAILS: ${sub.toUpperCase()} =====\n\n${text}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
79
|
+
writeFileSync(outFile, out, 'utf8');
|
|
80
|
+
console.error(`saved ${out.length} chars -> ${outFile}`);
|
|
81
|
+
await browser.close(); // detaches CDP connection only, Chrome keeps running
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Ensure a CDP Chrome is up on :9222 (adapted from iucn-mono qa-kit).
|
|
4
|
+
*
|
|
5
|
+
* If something already listens on the port (e.g. the iucn-mono QA browser,
|
|
6
|
+
* where LinkedIn is logged in) — reuse it. Otherwise launch Chrome with
|
|
7
|
+
* work-finder's own persistent profile (.cdp-browser-profile/, git-ignored),
|
|
8
|
+
* so logins survive restarts.
|
|
9
|
+
*
|
|
10
|
+
* Env overrides: CHROME_PATH, PORT (default 9222), WF_HEADLESS=1
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from 'node:child_process';
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { resolve, dirname } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
|
|
17
|
+
const PORT = Number(process.env.PORT) || 9222;
|
|
18
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
19
|
+
const PROFILE_DIR = resolve(ROOT, '.cdp-browser-profile');
|
|
20
|
+
|
|
21
|
+
const CHROME_CANDIDATES = {
|
|
22
|
+
darwin: [
|
|
23
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
24
|
+
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
25
|
+
],
|
|
26
|
+
linux: ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium'],
|
|
27
|
+
win32: [
|
|
28
|
+
process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe` : null,
|
|
29
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
30
|
+
].filter(Boolean),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
async function probeCDP() {
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(`http://localhost:${PORT}/json/version`, { signal: AbortSignal.timeout(1500) });
|
|
36
|
+
return res.ok;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function ensureBrowser() {
|
|
43
|
+
if (await probeCDP()) {
|
|
44
|
+
console.error(`[browser] CDP already up on :${PORT}, reusing.`);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
const chromePath = process.env.CHROME_PATH
|
|
48
|
+
|| (CHROME_CANDIDATES[process.platform] || []).find(p => existsSync(p));
|
|
49
|
+
if (!chromePath) {
|
|
50
|
+
console.error('[browser] Chrome not found; set CHROME_PATH.');
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const headless = /^(1|true)$/i.test(process.env.WF_HEADLESS || '');
|
|
54
|
+
const args = [
|
|
55
|
+
`--remote-debugging-port=${PORT}`,
|
|
56
|
+
`--user-data-dir=${PROFILE_DIR}`,
|
|
57
|
+
'--no-first-run',
|
|
58
|
+
...(headless ? ['--headless=new', '--disable-gpu'] : []),
|
|
59
|
+
];
|
|
60
|
+
console.error(`[browser] Launching Chrome${headless ? ' (headless)' : ''} on :${PORT}…`);
|
|
61
|
+
const child = spawn(chromePath, args, { detached: true, stdio: 'ignore' });
|
|
62
|
+
child.unref();
|
|
63
|
+
const t0 = Date.now();
|
|
64
|
+
while (Date.now() - t0 < 15_000) {
|
|
65
|
+
if (await probeCDP()) {
|
|
66
|
+
console.error('[browser] Ready.');
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
await new Promise(r => setTimeout(r, 300));
|
|
70
|
+
}
|
|
71
|
+
console.error(`[browser] Chrome did not respond on :${PORT} within 15s.`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
76
|
+
const ok = await ensureBrowser();
|
|
77
|
+
process.exit(ok ? 0 : 1);
|
|
78
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Open a URL in a new tab of the CDP browser, screenshot, close. Usage: node scripts/screenshot.mjs <url> <out.png> [width] */
|
|
3
|
+
const PW = process.env.PLAYWRIGHT_CORE
|
|
4
|
+
|| '/Users/dimalesnak/Desktop/www/iucn-mono/node_modules/playwright-core/index.mjs';
|
|
5
|
+
const { chromium } = await import(PW);
|
|
6
|
+
|
|
7
|
+
const [url, out, width] = process.argv.slice(2);
|
|
8
|
+
const browser = await chromium.connectOverCDP(process.env.CDP_ENDPOINT || 'http://localhost:9222');
|
|
9
|
+
const context = browser.contexts()[0];
|
|
10
|
+
const page = await context.newPage();
|
|
11
|
+
await page.setViewportSize({ width: Number(width) || 1400, height: 950 });
|
|
12
|
+
await page.goto(url, { waitUntil: 'networkidle', timeout: 20_000 }).catch(() => {});
|
|
13
|
+
await page.waitForTimeout(800);
|
|
14
|
+
await page.screenshot({ path: out, fullPage: false });
|
|
15
|
+
await page.close();
|
|
16
|
+
await browser.close();
|
|
17
|
+
console.error('saved', out);
|