@commandgarden/cli 1.4.1 → 2.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/dist/main.js +6 -12
- package/node_modules/@commandgarden/app/dist/client/assets/index-CThI0UCl.css +1 -0
- package/node_modules/@commandgarden/app/dist/client/assets/index-WANip_um.js +252 -0
- package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
- package/node_modules/@commandgarden/app/dist/server/journal/journal.config.d.ts +25 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.config.js +31 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.service.d.ts +37 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.service.js +142 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.types.d.ts +91 -0
- package/node_modules/@commandgarden/app/dist/server/journal/journal.types.js +4 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.d.ts +21 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.js +72 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/jira.source.d.ts +15 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/jira.source.js +42 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.d.ts +21 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.js +25 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/timetracking.source.d.ts +17 -0
- package/node_modules/@commandgarden/app/dist/server/journal/sources/timetracking.source.js +83 -0
- package/node_modules/@commandgarden/app/dist/server/routes/index.js +2 -0
- package/node_modules/@commandgarden/app/dist/server/routes/journal.d.ts +9 -0
- package/node_modules/@commandgarden/app/dist/server/routes/journal.js +56 -0
- package/node_modules/@commandgarden/chrome/dist/content-script.js +84 -2
- package/node_modules/@commandgarden/chrome/dist/content-script.js.map +2 -2
- package/node_modules/@commandgarden/chrome/dist/service-worker.js +73 -8
- package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +3 -3
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.eval.js +143 -0
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.yaml +70 -0
- package/node_modules/@commandgarden/daemon/connectors/gcs-kb-content.yaml +58 -0
- package/node_modules/@commandgarden/daemon/connectors/gcs-kb-pages.yaml +47 -0
- package/node_modules/@commandgarden/daemon/connectors/jira-my-tickets.eval.js +115 -0
- package/node_modules/@commandgarden/daemon/connectors/jira-my-tickets.yaml +54 -0
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.eval.js +186 -0
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.yaml +41 -0
- package/node_modules/@commandgarden/daemon/connectors/socket-security-news.yaml +63 -0
- package/node_modules/@commandgarden/daemon/connectors/tokenmaster-client-trustedby.yaml +62 -0
- package/node_modules/@commandgarden/daemon/connectors/tokenmaster-clients-list.yaml +55 -0
- package/node_modules/@commandgarden/daemon/connectors/wiz-blog-security.eval.js +29 -0
- package/node_modules/@commandgarden/daemon/connectors/wiz-blog-security.yaml +44 -0
- package/node_modules/@commandgarden/daemon/dist/daemon-runner.d.ts +12 -0
- package/node_modules/@commandgarden/daemon/dist/daemon-runner.d.ts.map +1 -0
- package/node_modules/@commandgarden/daemon/dist/daemon-runner.js +65 -0
- package/node_modules/@commandgarden/daemon/dist/daemon-runner.js.map +1 -0
- package/node_modules/@commandgarden/daemon/dist/server.d.ts.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/server.js +87 -13
- package/node_modules/@commandgarden/daemon/dist/server.js.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/transforms.d.ts +3 -0
- package/node_modules/@commandgarden/daemon/dist/transforms.d.ts.map +1 -0
- package/node_modules/@commandgarden/daemon/dist/transforms.js +36 -0
- package/node_modules/@commandgarden/daemon/dist/transforms.js.map +1 -0
- package/node_modules/@commandgarden/daemon/package.json +4 -2
- package/node_modules/@commandgarden/shared/dist/connector.d.ts +175 -0
- package/node_modules/@commandgarden/shared/dist/connector.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/connector.js +2 -0
- package/node_modules/@commandgarden/shared/dist/connector.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/expression/evaluator.d.ts +2 -0
- package/node_modules/@commandgarden/shared/dist/expression/evaluator.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/expression/evaluator.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/expression/filters.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/expression/filters.js +5 -0
- package/node_modules/@commandgarden/shared/dist/expression/filters.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/fan-out.d.ts +28 -0
- package/node_modules/@commandgarden/shared/dist/fan-out.d.ts.map +1 -0
- package/node_modules/@commandgarden/shared/dist/fan-out.js +55 -0
- package/node_modules/@commandgarden/shared/dist/fan-out.js.map +1 -0
- package/node_modules/@commandgarden/shared/dist/index.d.ts +2 -1
- package/node_modules/@commandgarden/shared/dist/index.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/index.js +3 -1
- package/node_modules/@commandgarden/shared/dist/index.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/loader.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/loader.js +17 -0
- package/node_modules/@commandgarden/shared/dist/loader.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/pipeline.d.ts +223 -1
- package/node_modules/@commandgarden/shared/dist/pipeline.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/pipeline.js +58 -2
- package/node_modules/@commandgarden/shared/dist/pipeline.js.map +1 -1
- package/node_modules/@commandgarden/shared/dist/protocol.d.ts +1 -0
- package/node_modules/@commandgarden/shared/dist/protocol.d.ts.map +1 -1
- package/node_modules/@commandgarden/shared/dist/protocol.js.map +1 -1
- package/package.json +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/index-B-_w54e9.css +0 -1
- package/node_modules/@commandgarden/app/dist/client/assets/index-Bb1BOK1E.js +0 -252
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journal Fastify route — POST /api/journal/generate.
|
|
3
|
+
* Reads journal config from user preferences (SQLite), instantiates
|
|
4
|
+
* sources with that config, and generates the weekly report.
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { DaemonClient } from '@commandgarden/shared';
|
|
8
|
+
import type { AppStore } from '../store.js';
|
|
9
|
+
export declare function journalRoutes(app: FastifyInstance, daemon: DaemonClient, store: AppStore): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journal Fastify route — POST /api/journal/generate.
|
|
3
|
+
* Reads journal config from user preferences (SQLite), instantiates
|
|
4
|
+
* sources with that config, and generates the weekly report.
|
|
5
|
+
*/
|
|
6
|
+
import { getJournalConfig } from '../journal/journal.config.js';
|
|
7
|
+
import { GitSource } from '../journal/sources/git.source.js';
|
|
8
|
+
import { JiraSource } from '../journal/sources/jira.source.js';
|
|
9
|
+
import { TimetrackingSource } from '../journal/sources/timetracking.source.js';
|
|
10
|
+
import { MeetingsSource } from '../journal/sources/meetings.source.js';
|
|
11
|
+
import { JournalService } from '../journal/journal.service.js';
|
|
12
|
+
export function journalRoutes(app, daemon, store) {
|
|
13
|
+
app.post('/api/journal/generate', async (req, reply) => {
|
|
14
|
+
const body = req.body;
|
|
15
|
+
// Validate weekStart is present and matches YYYY-MM-DD format
|
|
16
|
+
if (!body?.weekStart || !/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/.test(body.weekStart)) {
|
|
17
|
+
return reply.code(400).send({
|
|
18
|
+
ok: false,
|
|
19
|
+
error: 'weekStart is required and must be YYYY-MM-DD format',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// Build config from user preferences (configured via GUI Config page)
|
|
23
|
+
const config = getJournalConfig(store);
|
|
24
|
+
// Check that required settings are configured
|
|
25
|
+
if (!config.azureDevOps.org || config.azureDevOps.repos.length === 0) {
|
|
26
|
+
return reply.code(400).send({
|
|
27
|
+
ok: false,
|
|
28
|
+
error: 'Journal not configured. Go to Configuration → Journal Settings and set your ADO org and repos.',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const start = Date.now();
|
|
33
|
+
// Sources receive config from preferences — no env vars needed
|
|
34
|
+
const git = new GitSource(daemon, config);
|
|
35
|
+
const jira = new JiraSource(daemon);
|
|
36
|
+
const timetracking = new TimetrackingSource(daemon, config);
|
|
37
|
+
const meetings = new MeetingsSource(daemon);
|
|
38
|
+
const service = new JournalService(git, timetracking, meetings, jira);
|
|
39
|
+
const result = await service.generate({ weekStart: body.weekStart });
|
|
40
|
+
// Audit log (non-blocking — failure should not break the response)
|
|
41
|
+
const durationMs = Date.now() - start;
|
|
42
|
+
daemon.post('/api/audit/log', {
|
|
43
|
+
command: 'journal generate',
|
|
44
|
+
args: { weekStart: body.weekStart },
|
|
45
|
+
status: result.status,
|
|
46
|
+
durationMs,
|
|
47
|
+
}).catch(() => { });
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
52
|
+
console.error('[journal] generate error:', message);
|
|
53
|
+
return reply.code(500).send({ ok: false, error: message });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -43,6 +43,61 @@
|
|
|
43
43
|
return record;
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
+
function extractHtml(selector) {
|
|
47
|
+
const el = document.querySelector(selector);
|
|
48
|
+
if (!el) throw new Error(`Element "${selector}" not found`);
|
|
49
|
+
return el.innerHTML;
|
|
50
|
+
}
|
|
51
|
+
function extractTree(rootSelector, group, leaf, pathSeparator) {
|
|
52
|
+
const root = document.querySelector(rootSelector);
|
|
53
|
+
if (!root) throw new Error(`Root "${rootSelector}" not found`);
|
|
54
|
+
function extractField(el, spec) {
|
|
55
|
+
if (spec === "textContent") return el.textContent?.trim().replace(/\s+/g, " ") ?? "";
|
|
56
|
+
if (spec === "href") return el.getAttribute("href") ?? "";
|
|
57
|
+
if (spec.startsWith("attr:")) return el.getAttribute(spec.slice(5)) ?? "";
|
|
58
|
+
return el.textContent?.trim() ?? "";
|
|
59
|
+
}
|
|
60
|
+
function walk(container, ancestors, depth) {
|
|
61
|
+
const results = [];
|
|
62
|
+
for (const child of Array.from(container.children)) {
|
|
63
|
+
if (child.matches(leaf.match)) {
|
|
64
|
+
const row = {};
|
|
65
|
+
for (const [name, spec] of Object.entries(leaf.fields)) {
|
|
66
|
+
row[name] = extractField(child, spec);
|
|
67
|
+
}
|
|
68
|
+
const title = row.title || child.textContent?.trim() || "";
|
|
69
|
+
const section = ancestors.length > 0 ? ancestors[0] : title;
|
|
70
|
+
const pathParts = [...ancestors, title];
|
|
71
|
+
row.section = section;
|
|
72
|
+
row.path = pathParts.join(pathSeparator);
|
|
73
|
+
row.depth = depth;
|
|
74
|
+
results.push(row);
|
|
75
|
+
} else if (child.matches(group.match)) {
|
|
76
|
+
const titleEl = child.querySelector(group.title);
|
|
77
|
+
const groupTitle = titleEl?.textContent?.trim().replace(/\s+/g, " ") ?? "";
|
|
78
|
+
const childContainer = child.querySelector(group.children);
|
|
79
|
+
if (childContainer) {
|
|
80
|
+
results.push(...walk(childContainer, [...ancestors, groupTitle], depth + 1));
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
results.push(...walk(child, ancestors, depth));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
return walk(root, [], 0);
|
|
89
|
+
}
|
|
90
|
+
async function clickAll(selector, pause, maxRounds, settle) {
|
|
91
|
+
for (let round = 0; round < maxRounds; round++) {
|
|
92
|
+
const elements = document.querySelectorAll(selector);
|
|
93
|
+
if (elements.length === 0) break;
|
|
94
|
+
for (const el of Array.from(elements)) {
|
|
95
|
+
el.click();
|
|
96
|
+
if (pause > 0) await new Promise((r) => setTimeout(r, pause));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (settle > 0) await new Promise((r) => setTimeout(r, settle));
|
|
100
|
+
}
|
|
46
101
|
async function clickElement(selector) {
|
|
47
102
|
const el = document.querySelector(selector);
|
|
48
103
|
if (!el) throw new Error(`Element "${selector}" not found`);
|
|
@@ -86,19 +141,46 @@
|
|
|
86
141
|
return void 0;
|
|
87
142
|
case "extract":
|
|
88
143
|
return extractData(p.selector, p.fields);
|
|
144
|
+
case "extract_html":
|
|
145
|
+
return extractHtml(p.selector);
|
|
146
|
+
case "extract_tree":
|
|
147
|
+
return extractTree(
|
|
148
|
+
p.root,
|
|
149
|
+
p.group,
|
|
150
|
+
p.leaf,
|
|
151
|
+
p.pathSeparator ?? " / "
|
|
152
|
+
);
|
|
89
153
|
case "click":
|
|
90
154
|
await clickElement(p.selector);
|
|
91
155
|
return void 0;
|
|
156
|
+
case "click_all":
|
|
157
|
+
await clickAll(
|
|
158
|
+
p.selector,
|
|
159
|
+
p.pause ?? 200,
|
|
160
|
+
p.maxRounds ?? 10,
|
|
161
|
+
p.settle ?? 300
|
|
162
|
+
);
|
|
163
|
+
return void 0;
|
|
92
164
|
case "type":
|
|
93
165
|
await typeIntoElement(p.selector, p.value);
|
|
94
166
|
return void 0;
|
|
95
|
-
case "fetch":
|
|
96
|
-
|
|
167
|
+
case "fetch": {
|
|
168
|
+
const result = await fetchFromPage(
|
|
97
169
|
p.url,
|
|
98
170
|
p.method,
|
|
99
171
|
p.headers,
|
|
100
172
|
p.body
|
|
101
173
|
);
|
|
174
|
+
if (p.dataPath && result != null && typeof result === "object" && !Array.isArray(result)) {
|
|
175
|
+
let nested = result;
|
|
176
|
+
for (const key of p.dataPath.split(".")) {
|
|
177
|
+
if (nested == null || typeof nested !== "object") return [];
|
|
178
|
+
nested = nested[key];
|
|
179
|
+
}
|
|
180
|
+
return Array.isArray(nested) ? nested : [];
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
102
184
|
default:
|
|
103
185
|
throw new Error(`Unknown action: ${req.action}`);
|
|
104
186
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/messages.ts", "../src/content/dom-executor.ts", "../src/content/content-script.ts"],
|
|
4
|
-
"sourcesContent": ["// src/messages.ts\nconst randomUUID = () => crypto.randomUUID();\n\nexport type DomAction = 'wait' | 'extract' | 'click' | 'type' | 'fetch';\n\nexport interface DomRequest {\n id: string;\n action: DomAction;\n params: Record<string, unknown>;\n}\n\nexport interface DomResponse {\n requestId: string;\n ok: boolean;\n data?: unknown;\n error?: string;\n}\n\nexport function createDomRequest(action: DomAction, params: Record<string, unknown>): DomRequest {\n return { id: randomUUID(), action, params };\n}\n\nexport function createDomResponse(\n requestId: string, ok: boolean, data?: unknown, error?: string,\n): DomResponse {\n return { requestId, ok, data, error };\n}\n\nexport function isDomRequest(value: unknown): value is DomRequest {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return typeof obj.id === 'string' && typeof obj.action === 'string' && typeof obj.params === 'object';\n}\n\nexport function isDomResponse(value: unknown): value is DomResponse {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return typeof obj.requestId === 'string' && typeof obj.ok === 'boolean';\n}\n", "// src/content/dom-executor.ts\n\nexport function waitForSelector(selector: string, timeout: number): Promise<void> {\n return new Promise((resolve, reject) => {\n if (document.querySelector(selector)) { resolve(); return; }\n const interval = 100;\n let elapsed = 0;\n const timer = setInterval(() => {\n if (document.querySelector(selector)) { clearInterval(timer); resolve(); return; }\n elapsed += interval;\n if (elapsed >= timeout) {\n clearInterval(timer);\n reject(new Error(`Selector \"${selector}\" timed out after ${timeout}ms`));\n }\n }, interval);\n });\n}\n\nexport function extractData(\n rowSelector: string,\n fields: Record<string, string>,\n): Record<string, string>[] {\n const rows = document.querySelectorAll(rowSelector);\n return Array.from(rows).map(row => {\n const record: Record<string, string> = {};\n for (const [name, selector] of Object.entries(fields)) {\n record[name] = row.querySelector(selector)?.textContent?.trim() ?? '';\n }\n return record;\n });\n}\n\nexport async function clickElement(selector: string): Promise<void> {\n const el = document.querySelector(selector);\n if (!el) throw new Error(`Element \"${selector}\" not found`);\n (el as HTMLElement).click();\n}\n\nexport async function typeIntoElement(selector: string, value: string): Promise<void> {\n const el = document.querySelector(selector) as HTMLInputElement | null;\n if (!el) throw new Error(`Element \"${selector}\" not found`);\n el.focus();\n el.value = value;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\nexport async function fetchFromPage(\n url: string, method = 'GET', headers?: Record<string, string>, body?: string,\n): Promise<unknown> {\n const resp = await fetch(url, {\n method, headers, body, credentials: 'include',\n });\n const contentType = resp.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) return resp.json();\n return resp.text();\n}\n", "// src/content/content-script.ts\nimport { isDomRequest, createDomResponse, type DomRequest } from '../messages.js';\nimport { waitForSelector, extractData, clickElement, typeIntoElement, fetchFromPage } from './dom-executor.js';\n\nchrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {\n if (!isDomRequest(message)) return false;\n const req = message as DomRequest;\n handleRequest(req).then(\n (data) => sendResponse(createDomResponse(req.id, true, data)),\n (err) => sendResponse(createDomResponse(req.id, false, undefined, err.message)),\n );\n return true; // Keep channel open for async response\n});\n\nasync function handleRequest(req: DomRequest): Promise<unknown> {\n const p = req.params;\n switch (req.action) {\n case 'wait':\n await waitForSelector(p.selector as string, (p.timeout as number) ?? 10000);\n return undefined;\n case 'extract':\n return extractData(p.selector as string, p.fields as Record<string, string>);\n case 'click':\n await clickElement(p.selector as string);\n return undefined;\n case 'type':\n await typeIntoElement(p.selector as string, p.value as string);\n return undefined;\n case 'fetch'
|
|
5
|
-
"mappings": ";;;AAsBO,WAAS,kBACd,WAAmB,IAAa,MAAgB,OACnC;AACb,WAAO,EAAE,WAAW,IAAI,MAAM,MAAM;AAAA,EACtC;AAEO,WAAS,aAAa,OAAqC;AAChE,QAAI,SAAS,QAAQ,OAAO,UAAU,SAAU,QAAO;AACvD,UAAM,MAAM;AACZ,WAAO,OAAO,IAAI,OAAO,YAAY,OAAO,IAAI,WAAW,YAAY,OAAO,IAAI,WAAW;AAAA,EAC/F;;;AC9BO,WAAS,gBAAgB,UAAkB,SAAgC;AAChF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,SAAS,cAAc,QAAQ,GAAG;AAAE,gBAAQ;AAAG;AAAA,MAAQ;AAC3D,YAAM,WAAW;AACjB,UAAI,UAAU;AACd,YAAM,QAAQ,YAAY,MAAM;AAC9B,YAAI,SAAS,cAAc,QAAQ,GAAG;AAAE,wBAAc,KAAK;AAAG,kBAAQ;AAAG;AAAA,QAAQ;AACjF,mBAAW;AACX,YAAI,WAAW,SAAS;AACtB,wBAAc,KAAK;AACnB,iBAAO,IAAI,MAAM,aAAa,QAAQ,qBAAqB,OAAO,IAAI,CAAC;AAAA,QACzE;AAAA,MACF,GAAG,QAAQ;AAAA,IACb,CAAC;AAAA,EACH;AAEO,WAAS,YACd,aACA,QAC0B;AAC1B,UAAM,OAAO,SAAS,iBAAiB,WAAW;AAClD,WAAO,MAAM,KAAK,IAAI,EAAE,IAAI,SAAO;AACjC,YAAM,SAAiC,CAAC;AACxC,iBAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,MAAM,GAAG;AACrD,eAAO,IAAI,IAAI,IAAI,cAAc,QAAQ,GAAG,aAAa,KAAK,KAAK;AAAA,MACrE;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,iBAAsB,aAAa,UAAiC;AAClE,UAAM,KAAK,SAAS,cAAc,QAAQ;AAC1C,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,YAAY,QAAQ,aAAa;AAC1D,IAAC,GAAmB,MAAM;AAAA,EAC5B;AAEA,iBAAsB,gBAAgB,UAAkB,OAA8B;AACpF,UAAM,KAAK,SAAS,cAAc,QAAQ;AAC1C,QAAI,CAAC,GAAI,OAAM,IAAI,MAAM,YAAY,QAAQ,aAAa;AAC1D,OAAG,MAAM;AACT,OAAG,QAAQ;AACX,OAAG,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AACtD,OAAG,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAAA,EACzD;AAEA,iBAAsB,cACpB,KAAa,SAAS,OAAO,SAAkC,MAC7C;AAClB,UAAM,OAAO,MAAM,MAAM,KAAK;AAAA,MAC5B;AAAA,MAAQ;AAAA,MAAS;AAAA,MAAM,aAAa;AAAA,IACtC,CAAC;AACD,UAAM,cAAc,KAAK,QAAQ,IAAI,cAAc,KAAK;AACxD,QAAI,YAAY,SAAS,kBAAkB,EAAG,QAAO,KAAK,KAAK;AAC/D,WAAO,KAAK,KAAK;AAAA,EACnB;;;
|
|
4
|
+
"sourcesContent": ["// src/messages.ts\nconst randomUUID = () => crypto.randomUUID();\n\nexport type DomAction = 'wait' | 'extract' | 'extract_tree' | 'extract_html' | 'click' | 'click_all' | 'type' | 'fetch';\n\nexport interface DomRequest {\n id: string;\n action: DomAction;\n params: Record<string, unknown>;\n}\n\nexport interface DomResponse {\n requestId: string;\n ok: boolean;\n data?: unknown;\n error?: string;\n}\n\nexport function createDomRequest(action: DomAction, params: Record<string, unknown>): DomRequest {\n return { id: randomUUID(), action, params };\n}\n\nexport function createDomResponse(\n requestId: string, ok: boolean, data?: unknown, error?: string,\n): DomResponse {\n return { requestId, ok, data, error };\n}\n\nexport function isDomRequest(value: unknown): value is DomRequest {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return typeof obj.id === 'string' && typeof obj.action === 'string' && typeof obj.params === 'object';\n}\n\nexport function isDomResponse(value: unknown): value is DomResponse {\n if (value == null || typeof value !== 'object') return false;\n const obj = value as Record<string, unknown>;\n return typeof obj.requestId === 'string' && typeof obj.ok === 'boolean';\n}\n", "// src/content/dom-executor.ts\n\nexport function waitForSelector(selector: string, timeout: number): Promise<void> {\n return new Promise((resolve, reject) => {\n if (document.querySelector(selector)) { resolve(); return; }\n const interval = 100;\n let elapsed = 0;\n const timer = setInterval(() => {\n if (document.querySelector(selector)) { clearInterval(timer); resolve(); return; }\n elapsed += interval;\n if (elapsed >= timeout) {\n clearInterval(timer);\n reject(new Error(`Selector \"${selector}\" timed out after ${timeout}ms`));\n }\n }, interval);\n });\n}\n\nexport function extractData(\n rowSelector: string,\n fields: Record<string, string>,\n): Record<string, string>[] {\n const rows = document.querySelectorAll(rowSelector);\n return Array.from(rows).map(row => {\n const record: Record<string, string> = {};\n for (const [name, selector] of Object.entries(fields)) {\n record[name] = row.querySelector(selector)?.textContent?.trim() ?? '';\n }\n return record;\n });\n}\n\nexport function extractHtml(selector: string): string {\n const el = document.querySelector(selector);\n if (!el) throw new Error(`Element \"${selector}\" not found`);\n return el.innerHTML;\n}\n\nexport function extractTree(\n rootSelector: string,\n group: { match: string; title: string; children: string },\n leaf: { match: string; fields: Record<string, string> },\n pathSeparator: string,\n): Record<string, unknown>[] {\n const root = document.querySelector(rootSelector);\n if (!root) throw new Error(`Root \"${rootSelector}\" not found`);\n\n function extractField(el: Element, spec: string): string {\n if (spec === 'textContent') return el.textContent?.trim().replace(/\\s+/g, ' ') ?? '';\n if (spec === 'href') return el.getAttribute('href') ?? '';\n if (spec.startsWith('attr:')) return el.getAttribute(spec.slice(5)) ?? '';\n return el.textContent?.trim() ?? '';\n }\n\n function walk(container: Element, ancestors: string[], depth: number): Record<string, unknown>[] {\n const results: Record<string, unknown>[] = [];\n for (const child of Array.from(container.children)) {\n if (child.matches(leaf.match)) {\n const row: Record<string, unknown> = {};\n for (const [name, spec] of Object.entries(leaf.fields)) {\n row[name] = extractField(child, spec);\n }\n const title = (row.title as string) || child.textContent?.trim() || '';\n const section = ancestors.length > 0 ? ancestors[0] : title;\n const pathParts = [...ancestors, title];\n row.section = section;\n row.path = pathParts.join(pathSeparator);\n row.depth = depth;\n results.push(row);\n } else if (child.matches(group.match)) {\n const titleEl = child.querySelector(group.title);\n const groupTitle = titleEl?.textContent?.trim().replace(/\\s+/g, ' ') ?? '';\n const childContainer = child.querySelector(group.children);\n if (childContainer) {\n results.push(...walk(childContainer, [...ancestors, groupTitle], depth + 1));\n }\n } else {\n results.push(...walk(child, ancestors, depth));\n }\n }\n return results;\n }\n\n return walk(root, [], 0);\n}\n\nexport async function clickAll(\n selector: string, pause: number, maxRounds: number, settle: number,\n): Promise<void> {\n for (let round = 0; round < maxRounds; round++) {\n const elements = document.querySelectorAll(selector);\n if (elements.length === 0) break;\n for (const el of Array.from(elements)) {\n (el as HTMLElement).click();\n if (pause > 0) await new Promise(r => setTimeout(r, pause));\n }\n }\n if (settle > 0) await new Promise(r => setTimeout(r, settle));\n}\n\nexport async function clickElement(selector: string): Promise<void> {\n const el = document.querySelector(selector);\n if (!el) throw new Error(`Element \"${selector}\" not found`);\n (el as HTMLElement).click();\n}\n\nexport async function typeIntoElement(selector: string, value: string): Promise<void> {\n const el = document.querySelector(selector) as HTMLInputElement | null;\n if (!el) throw new Error(`Element \"${selector}\" not found`);\n el.focus();\n el.value = value;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\nexport async function fetchFromPage(\n url: string, method = 'GET', headers?: Record<string, string>, body?: string,\n): Promise<unknown> {\n const resp = await fetch(url, {\n method, headers, body, credentials: 'include',\n });\n const contentType = resp.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) return resp.json();\n return resp.text();\n}\n", "// src/content/content-script.ts\nimport { isDomRequest, createDomResponse, type DomRequest } from '../messages.js';\nimport { waitForSelector, extractData, extractHtml, extractTree, clickElement, clickAll, typeIntoElement, fetchFromPage } from './dom-executor.js';\n\nchrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {\n if (!isDomRequest(message)) return false;\n const req = message as DomRequest;\n handleRequest(req).then(\n (data) => sendResponse(createDomResponse(req.id, true, data)),\n (err) => sendResponse(createDomResponse(req.id, false, undefined, err.message)),\n );\n return true; // Keep channel open for async response\n});\n\nasync function handleRequest(req: DomRequest): Promise<unknown> {\n const p = req.params;\n switch (req.action) {\n case 'wait':\n await waitForSelector(p.selector as string, (p.timeout as number) ?? 10000);\n return undefined;\n case 'extract':\n return extractData(p.selector as string, p.fields as Record<string, string>);\n case 'extract_html':\n return extractHtml(p.selector as string);\n case 'extract_tree':\n return extractTree(\n p.root as string,\n p.group as { match: string; title: string; children: string },\n p.leaf as { match: string; fields: Record<string, string> },\n (p.pathSeparator as string) ?? ' / ',\n );\n case 'click':\n await clickElement(p.selector as string);\n return undefined;\n case 'click_all':\n await clickAll(\n p.selector as string,\n (p.pause as number) ?? 200,\n (p.maxRounds as number) ?? 10,\n (p.settle as number) ?? 300,\n );\n return undefined;\n case 'type':\n await typeIntoElement(p.selector as string, p.value as string);\n return undefined;\n case 'fetch': {\n const result = await fetchFromPage(\n p.url as string, p.method as string,\n p.headers as Record<string, string>, p.body as string,\n );\n if (p.dataPath && result != null && typeof result === 'object' && !Array.isArray(result)) {\n let nested: unknown = result;\n for (const key of (p.dataPath as string).split('.')) {\n if (nested == null || typeof nested !== 'object') return [];\n nested = (nested as Record<string, unknown>)[key];\n }\n return Array.isArray(nested) ? nested : [];\n }\n return result;\n }\n default:\n throw new Error(`Unknown action: ${req.action}`);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4227,7 +4227,10 @@ var STEP_CAPABILITY_MAP = {
|
|
|
4227
4227
|
navigate: "navigate",
|
|
4228
4228
|
wait: "navigate",
|
|
4229
4229
|
extract: "dom_read",
|
|
4230
|
+
extract_tree: "dom_read",
|
|
4231
|
+
extract_html: "dom_read",
|
|
4230
4232
|
click: "dom_write",
|
|
4233
|
+
click_all: "dom_write",
|
|
4231
4234
|
type: "dom_write",
|
|
4232
4235
|
intercept: "intercept_response",
|
|
4233
4236
|
cookie: "cookie_read",
|
|
@@ -4235,6 +4238,7 @@ var STEP_CAPABILITY_MAP = {
|
|
|
4235
4238
|
map: null,
|
|
4236
4239
|
filter: null,
|
|
4237
4240
|
set: null,
|
|
4241
|
+
transform: null,
|
|
4238
4242
|
js_evaluate: "js_evaluate"
|
|
4239
4243
|
};
|
|
4240
4244
|
var navigateStepSchema = external_exports.object({
|
|
@@ -4277,7 +4281,8 @@ var fetchStepSchema = external_exports.object({
|
|
|
4277
4281
|
method: external_exports.string().optional(),
|
|
4278
4282
|
headers: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
4279
4283
|
body: external_exports.string().optional(),
|
|
4280
|
-
as: external_exports.string().optional()
|
|
4284
|
+
as: external_exports.string().optional(),
|
|
4285
|
+
dataPath: external_exports.string().optional()
|
|
4281
4286
|
});
|
|
4282
4287
|
var mapStepSchema = external_exports.object({
|
|
4283
4288
|
step: external_exports.literal("map"),
|
|
@@ -4294,6 +4299,39 @@ var setStepSchema = external_exports.object({
|
|
|
4294
4299
|
name: external_exports.string(),
|
|
4295
4300
|
value: external_exports.string()
|
|
4296
4301
|
});
|
|
4302
|
+
var extractHtmlStepSchema = external_exports.object({
|
|
4303
|
+
step: external_exports.literal("extract_html"),
|
|
4304
|
+
selector: external_exports.string(),
|
|
4305
|
+
as: external_exports.string()
|
|
4306
|
+
});
|
|
4307
|
+
var transformStepSchema = external_exports.object({
|
|
4308
|
+
step: external_exports.literal("transform"),
|
|
4309
|
+
type: external_exports.string(),
|
|
4310
|
+
input: external_exports.string(),
|
|
4311
|
+
as: external_exports.string(),
|
|
4312
|
+
options: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
4313
|
+
});
|
|
4314
|
+
var extractTreeStepSchema = external_exports.object({
|
|
4315
|
+
step: external_exports.literal("extract_tree"),
|
|
4316
|
+
root: external_exports.string(),
|
|
4317
|
+
group: external_exports.object({
|
|
4318
|
+
match: external_exports.string(),
|
|
4319
|
+
title: external_exports.string(),
|
|
4320
|
+
children: external_exports.string()
|
|
4321
|
+
}),
|
|
4322
|
+
leaf: external_exports.object({
|
|
4323
|
+
match: external_exports.string(),
|
|
4324
|
+
fields: external_exports.record(external_exports.string(), external_exports.string())
|
|
4325
|
+
}),
|
|
4326
|
+
pathSeparator: external_exports.string().optional()
|
|
4327
|
+
});
|
|
4328
|
+
var clickAllStepSchema = external_exports.object({
|
|
4329
|
+
step: external_exports.literal("click_all"),
|
|
4330
|
+
selector: external_exports.string(),
|
|
4331
|
+
pause: external_exports.number().positive().optional(),
|
|
4332
|
+
maxRounds: external_exports.number().positive().optional(),
|
|
4333
|
+
settle: external_exports.number().nonnegative().optional()
|
|
4334
|
+
});
|
|
4297
4335
|
var jsEvaluateStepSchema = external_exports.object({
|
|
4298
4336
|
step: external_exports.literal("js_evaluate"),
|
|
4299
4337
|
code: external_exports.string().optional(),
|
|
@@ -4312,6 +4350,10 @@ var pipelineStepSchema = external_exports.discriminatedUnion("step", [
|
|
|
4312
4350
|
mapStepSchema,
|
|
4313
4351
|
filterStepSchema,
|
|
4314
4352
|
setStepSchema,
|
|
4353
|
+
extractHtmlStepSchema,
|
|
4354
|
+
transformStepSchema,
|
|
4355
|
+
extractTreeStepSchema,
|
|
4356
|
+
clickAllStepSchema,
|
|
4315
4357
|
jsEvaluateStepSchema
|
|
4316
4358
|
]);
|
|
4317
4359
|
|
|
@@ -4323,7 +4365,8 @@ var connectorArgSchema = external_exports.object({
|
|
|
4323
4365
|
required: external_exports.boolean().default(false),
|
|
4324
4366
|
default: external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()]).optional(),
|
|
4325
4367
|
help: external_exports.string().optional(),
|
|
4326
|
-
pattern: external_exports.string().optional()
|
|
4368
|
+
pattern: external_exports.string().optional(),
|
|
4369
|
+
enum: external_exports.array(external_exports.string()).optional()
|
|
4327
4370
|
});
|
|
4328
4371
|
var connectorColumnSchema = external_exports.object({
|
|
4329
4372
|
name: external_exports.string(),
|
|
@@ -4335,6 +4378,7 @@ var connectorSchema = external_exports.object({
|
|
|
4335
4378
|
version: external_exports.string(),
|
|
4336
4379
|
description: external_exports.string().optional(),
|
|
4337
4380
|
access: external_exports.enum(["read", "write"]).default("read"),
|
|
4381
|
+
vars: external_exports.record(external_exports.unknown()).optional(),
|
|
4338
4382
|
domains: external_exports.array(external_exports.string()).min(1),
|
|
4339
4383
|
capabilities: external_exports.array(capabilityEnum).min(1),
|
|
4340
4384
|
args: external_exports.array(connectorArgSchema).optional().default([]),
|
|
@@ -6776,7 +6820,12 @@ var BUILT_IN_FILTERS = {
|
|
|
6776
6820
|
number: (value) => Number(value),
|
|
6777
6821
|
trim: (value) => String(value).trim(),
|
|
6778
6822
|
upper: (value) => String(value).toUpperCase(),
|
|
6779
|
-
lower: (value) => String(value).toLowerCase()
|
|
6823
|
+
lower: (value) => String(value).toLowerCase(),
|
|
6824
|
+
lookup: (value, map2) => {
|
|
6825
|
+
if (map2 == null || typeof map2 !== "object")
|
|
6826
|
+
return void 0;
|
|
6827
|
+
return map2[String(value)];
|
|
6828
|
+
}
|
|
6780
6829
|
};
|
|
6781
6830
|
|
|
6782
6831
|
// ../shared/dist/expression/evaluator.js
|
|
@@ -6832,8 +6881,9 @@ var PipelineContext = class {
|
|
|
6832
6881
|
cookies = {};
|
|
6833
6882
|
data = [];
|
|
6834
6883
|
args;
|
|
6835
|
-
constructor(args) {
|
|
6884
|
+
constructor(args, initialVars) {
|
|
6836
6885
|
this.args = args;
|
|
6886
|
+
if (initialVars) Object.assign(this.vars, initialVars);
|
|
6837
6887
|
}
|
|
6838
6888
|
setVar(name, value) {
|
|
6839
6889
|
this.vars[name] = value;
|
|
@@ -6841,6 +6891,9 @@ var PipelineContext = class {
|
|
|
6841
6891
|
getVar(name) {
|
|
6842
6892
|
return this.vars[name];
|
|
6843
6893
|
}
|
|
6894
|
+
getVars() {
|
|
6895
|
+
return { ...this.vars };
|
|
6896
|
+
}
|
|
6844
6897
|
setCookies(cookies) {
|
|
6845
6898
|
Object.assign(this.cookies, cookies);
|
|
6846
6899
|
}
|
|
@@ -6861,7 +6914,8 @@ var PipelineContext = class {
|
|
|
6861
6914
|
const rowCtx = {
|
|
6862
6915
|
args: this.args,
|
|
6863
6916
|
vars: { ...this.vars, row },
|
|
6864
|
-
cookies: this.cookies
|
|
6917
|
+
cookies: this.cookies,
|
|
6918
|
+
row
|
|
6865
6919
|
};
|
|
6866
6920
|
mapped[key] = interpolate(expr, rowCtx);
|
|
6867
6921
|
}
|
|
@@ -6917,7 +6971,7 @@ var PipelineRunner = class {
|
|
|
6917
6971
|
}
|
|
6918
6972
|
}
|
|
6919
6973
|
async run(connector, args) {
|
|
6920
|
-
const ctx = new PipelineContext(args);
|
|
6974
|
+
const ctx = new PipelineContext(args, connector.vars);
|
|
6921
6975
|
let tabId = -1;
|
|
6922
6976
|
const stepSummaries = [];
|
|
6923
6977
|
try {
|
|
@@ -6935,6 +6989,7 @@ var PipelineRunner = class {
|
|
|
6935
6989
|
}
|
|
6936
6990
|
case "wait":
|
|
6937
6991
|
case "click":
|
|
6992
|
+
case "click_all":
|
|
6938
6993
|
await this.adapter.executeInContent(tabId, step);
|
|
6939
6994
|
break;
|
|
6940
6995
|
case "type":
|
|
@@ -6948,6 +7003,16 @@ var PipelineRunner = class {
|
|
|
6948
7003
|
ctx.setData(data);
|
|
6949
7004
|
break;
|
|
6950
7005
|
}
|
|
7006
|
+
case "extract_tree": {
|
|
7007
|
+
const treeData = await this.adapter.executeInContent(tabId, step);
|
|
7008
|
+
ctx.setData(treeData);
|
|
7009
|
+
break;
|
|
7010
|
+
}
|
|
7011
|
+
case "extract_html": {
|
|
7012
|
+
const html = await this.adapter.executeInContent(tabId, step);
|
|
7013
|
+
if (step.as) ctx.setVar(step.as, html);
|
|
7014
|
+
break;
|
|
7015
|
+
}
|
|
6951
7016
|
case "fetch": {
|
|
6952
7017
|
const fetchStep = {
|
|
6953
7018
|
...step,
|
|
@@ -7014,9 +7079,9 @@ var PipelineRunner = class {
|
|
|
7014
7079
|
throw err;
|
|
7015
7080
|
}
|
|
7016
7081
|
}
|
|
7017
|
-
return { id: "", ok: true, data: ctx.getData(), steps: stepSummaries };
|
|
7082
|
+
return { id: "", ok: true, data: ctx.getData(), vars: ctx.getVars(), steps: stepSummaries };
|
|
7018
7083
|
} catch (err) {
|
|
7019
|
-
return { id: "", ok: false, data: [], error: err instanceof Error ? err.message : String(err), steps: stepSummaries };
|
|
7084
|
+
return { id: "", ok: false, data: [], vars: {}, error: err instanceof Error ? err.message : String(err), steps: stepSummaries };
|
|
7020
7085
|
}
|
|
7021
7086
|
}
|
|
7022
7087
|
};
|