zd-agent-cli 0.1.1

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.
@@ -0,0 +1,316 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveGlobalOpts = resolveGlobalOpts;
7
+ exports.emitResult = emitResult;
8
+ exports.withZendeskBrowser = withZendeskBrowser;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const playwright_1 = require("playwright");
12
+ const browser_cdp_1 = require("./browser-cdp");
13
+ const constants_1 = require("./constants");
14
+ const config_1 = require("./config");
15
+ const storage_1 = require("./storage");
16
+ const automation_1 = require("./automation");
17
+ function resolveGlobalOpts(program) {
18
+ const opts = program.opts();
19
+ const env = process.env;
20
+ const loadedConfig = (0, config_1.loadResolvedConfig)({
21
+ cwd: process.cwd(),
22
+ configPath: opts.config || ''
23
+ });
24
+ const cfg = loadedConfig.config || {};
25
+ const queueCfg = loadedConfig.queueConfig || { defaultQueue: '', queues: {} };
26
+ const configValidation = (0, config_1.validateConfigContract)(cfg, queueCfg);
27
+ const cdpUrl = (0, config_1.pickString)({
28
+ cliValue: opts.cdpUrl,
29
+ cliSource: (0, config_1.safeOptionSource)(program, 'cdpUrl'),
30
+ envValue: env.ZENDESK_CDP_URL,
31
+ configValue: cfg.cdpUrl,
32
+ fallback: constants_1.DEFAULT_CDP_URL
33
+ });
34
+ let domain = (0, config_1.pickString)({
35
+ cliValue: opts.domain,
36
+ cliSource: (0, config_1.safeOptionSource)(program, 'domain'),
37
+ envValue: env.ZENDESK_DOMAIN,
38
+ configValue: cfg.domain,
39
+ fallback: constants_1.DEFAULT_DOMAIN
40
+ }).replace(/^https?:\/\//i, '').replace(/\/+$/, '');
41
+ if (domain.includes('/')) {
42
+ domain = domain.split('/')[0];
43
+ }
44
+ const startPath = (0, config_1.normalizeAgentPath)((0, config_1.pickString)({
45
+ cliValue: opts.startPath,
46
+ cliSource: (0, config_1.safeOptionSource)(program, 'startPath'),
47
+ envValue: env.ZENDESK_START_PATH,
48
+ configValue: cfg.startPath,
49
+ fallback: constants_1.DEFAULT_START_PATH
50
+ }), constants_1.DEFAULT_START_PATH);
51
+ if (startPath && !/^\/agent\//i.test(startPath)) {
52
+ throw new Error(`Invalid startPath "${startPath}". startPath must begin with "/agent/".`);
53
+ }
54
+ const startUrl = domain ? `https://${domain}${startPath}` : '';
55
+ const uiWaitMs = (0, config_1.pickNumber)({
56
+ cliValue: opts.uiWaitMs,
57
+ cliSource: (0, config_1.safeOptionSource)(program, 'uiWaitMs'),
58
+ envValue: env.ZENDESK_UI_WAIT_MS,
59
+ configValue: cfg.uiWaitMs,
60
+ fallback: constants_1.DEFAULT_UI_WAIT_MS
61
+ });
62
+ const storeRootRaw = (0, config_1.pickString)({
63
+ cliValue: opts.storeRoot,
64
+ cliSource: (0, config_1.safeOptionSource)(program, 'storeRoot'),
65
+ envValue: env.ZENDESK_STORE_ROOT,
66
+ configValue: cfg.storeRoot,
67
+ fallback: constants_1.DEFAULT_STORE_ROOT
68
+ });
69
+ const profileDirRaw = (0, config_1.pickString)({
70
+ cliValue: opts.profileDir,
71
+ cliSource: (0, config_1.safeOptionSource)(program, 'profileDir'),
72
+ envValue: env.ZENDESK_PROFILE_DIR,
73
+ configValue: cfg.profileDir,
74
+ fallback: constants_1.DEFAULT_PROFILE_DIR
75
+ });
76
+ const defaultQueue = (0, config_1.pickString)({
77
+ cliValue: '',
78
+ cliSource: '',
79
+ envValue: env.ZENDESK_DEFAULT_QUEUE,
80
+ configValue: queueCfg.defaultQueue,
81
+ fallback: ''
82
+ });
83
+ return {
84
+ cdpUrl,
85
+ domain,
86
+ startPath,
87
+ profileDir: (0, config_1.toAbsPath)(profileDirRaw, loadedConfig.repoRoot),
88
+ startUrl,
89
+ noLaunch: (0, config_1.pickBool)({
90
+ cliValue: opts.noLaunch,
91
+ cliSource: (0, config_1.safeOptionSource)(program, 'noLaunch'),
92
+ envValue: env.ZENDESK_NO_LAUNCH,
93
+ configValue: cfg.noLaunch,
94
+ fallback: false
95
+ }),
96
+ allowSharedCdp: (0, config_1.pickBool)({
97
+ cliValue: opts.allowSharedCdp,
98
+ cliSource: (0, config_1.safeOptionSource)(program, 'allowSharedCdp'),
99
+ envValue: env.ZENDESK_ALLOW_SHARED_CDP,
100
+ configValue: cfg.allowSharedCdp,
101
+ fallback: false
102
+ }),
103
+ autoPort: !(0, config_1.pickBool)({
104
+ cliValue: opts.autoPort === false,
105
+ cliSource: (0, config_1.safeOptionSource)(program, 'autoPort'),
106
+ envValue: env.ZENDESK_NO_AUTO_PORT,
107
+ configValue: cfg.noAutoPort,
108
+ fallback: false
109
+ }),
110
+ cdpPortSpan: Math.max(0, Math.floor((0, config_1.pickNumber)({
111
+ cliValue: opts.cdpPortSpan,
112
+ cliSource: (0, config_1.safeOptionSource)(program, 'cdpPortSpan'),
113
+ envValue: env.ZENDESK_CDP_PORT_SPAN,
114
+ configValue: cfg.cdpPortSpan,
115
+ fallback: 10
116
+ }))),
117
+ json: (0, config_1.pickBool)({
118
+ cliValue: opts.json,
119
+ cliSource: (0, config_1.safeOptionSource)(program, 'json'),
120
+ envValue: env.ZENDESK_JSON,
121
+ configValue: cfg.json,
122
+ fallback: false
123
+ }),
124
+ out: opts.out || '',
125
+ uiWaitMs,
126
+ background: !(0, config_1.pickBool)({
127
+ cliValue: opts.foreground,
128
+ cliSource: (0, config_1.safeOptionSource)(program, 'foreground'),
129
+ envValue: env.ZENDESK_FOREGROUND,
130
+ configValue: cfg.foreground,
131
+ fallback: false
132
+ }),
133
+ storeRoot: (0, config_1.toAbsPath)(storeRootRaw, loadedConfig.repoRoot),
134
+ store: !(0, config_1.pickBool)({
135
+ cliValue: opts.store === false,
136
+ cliSource: (0, config_1.safeOptionSource)(program, 'store'),
137
+ envValue: env.ZENDESK_NO_STORE,
138
+ configValue: cfg.noStore,
139
+ fallback: false
140
+ }),
141
+ cache: !(0, config_1.pickBool)({
142
+ cliValue: opts.cache === false,
143
+ cliSource: (0, config_1.safeOptionSource)(program, 'cache'),
144
+ envValue: env.ZENDESK_NO_CACHE,
145
+ configValue: cfg.noCache,
146
+ fallback: false
147
+ }),
148
+ cacheOnly: (0, config_1.pickBool)({
149
+ cliValue: opts.cacheOnly,
150
+ cliSource: (0, config_1.safeOptionSource)(program, 'cacheOnly'),
151
+ envValue: env.ZENDESK_CACHE_ONLY,
152
+ configValue: cfg.cacheOnly,
153
+ fallback: false
154
+ }),
155
+ cacheTtl: Math.max(0, Math.floor((0, config_1.pickNumber)({
156
+ cliValue: opts.cacheTtl,
157
+ cliSource: (0, config_1.safeOptionSource)(program, 'cacheTtl'),
158
+ envValue: env.ZENDESK_CACHE_TTL,
159
+ configValue: cfg.cacheTtl,
160
+ fallback: 120
161
+ }))),
162
+ defaultQueue,
163
+ queueAliases: queueCfg.queues,
164
+ configPath: loadedConfig.configPath,
165
+ repoRoot: loadedConfig.repoRoot,
166
+ configValidation
167
+ };
168
+ }
169
+ function emitResult(program, result) {
170
+ const globalOpts = resolveGlobalOpts(program);
171
+ const persisted = result && result.cacheHit ? null : (0, storage_1.persistOutput)(result, globalOpts);
172
+ const output = persisted ? { ...result, persisted } : result;
173
+ if (globalOpts.out) {
174
+ const outPath = path_1.default.resolve(globalOpts.out);
175
+ fs_1.default.mkdirSync(path_1.default.dirname(outPath), { recursive: true });
176
+ fs_1.default.writeFileSync(outPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8');
177
+ }
178
+ if (globalOpts.json) {
179
+ console.log(JSON.stringify(output, null, 2));
180
+ return;
181
+ }
182
+ if (output.command === 'read-ticket') {
183
+ console.log(`Ticket: ${output.ticketId || 'unknown'}`);
184
+ console.log(`Subject: ${output.subject || 'unknown'}`);
185
+ console.log(`Status: ${output.status || 'unknown'}`);
186
+ console.log(`Priority: ${output.priority || 'unknown'}`);
187
+ console.log(`Assignee: ${output.assignee || 'unknown'}`);
188
+ console.log(`Requester: ${output.requester || 'unknown'}`);
189
+ console.log(`URL: ${output.pageUrl}`);
190
+ if (output.cacheHit) {
191
+ console.log(`Cache: hit (${output.cacheAgeSeconds}s old)`);
192
+ }
193
+ if (output.persisted) {
194
+ console.log(`Stored: ${output.persisted.latestPath}`);
195
+ }
196
+ console.log('');
197
+ for (let i = 0; i < output.comments.length; i += 1) {
198
+ const row = output.comments[i];
199
+ console.log(`${i + 1}. [${row.author || 'Unknown'} @ ${row.time || 'time-unknown'}] ${row.text}`);
200
+ }
201
+ return;
202
+ }
203
+ if (output.command === 'read-queue') {
204
+ console.log(`Queue: ${output.queueName}`);
205
+ console.log(`URL: ${output.pageUrl}`);
206
+ console.log(`Tickets: ${output.resultCount}`);
207
+ if (output.persisted) {
208
+ console.log(`Stored: ${output.persisted.latestPath}`);
209
+ }
210
+ console.log('');
211
+ for (let i = 0; i < output.tickets.length; i += 1) {
212
+ const row = output.tickets[i];
213
+ console.log(`${i + 1}. #${row.ticketId || '?'} ${row.subject || '(no subject)'} [${row.status || 'unknown'}]`);
214
+ }
215
+ return;
216
+ }
217
+ if (output.command === 'search-tickets') {
218
+ console.log(`Query: ${output.query}`);
219
+ console.log(`URL: ${output.pageUrl}`);
220
+ console.log(`Hits: ${output.resultCount}`);
221
+ if (output.persisted) {
222
+ console.log(`Stored: ${output.persisted.latestPath}`);
223
+ }
224
+ console.log('');
225
+ for (let i = 0; i < output.results.length; i += 1) {
226
+ const row = output.results[i];
227
+ console.log(`${i + 1}. #${row.ticketId || '?'} ${row.title || '(no title)'}`);
228
+ if (row.snippet) {
229
+ console.log(` ${row.snippet}`);
230
+ }
231
+ if (row.url) {
232
+ console.log(` ${row.url}`);
233
+ }
234
+ }
235
+ return;
236
+ }
237
+ if (output.command === 'list-queues') {
238
+ console.log(`Domain: ${output.domain || 'unknown'}`);
239
+ console.log(`Default queue: ${output.defaultQueue || 'none'}`);
240
+ console.log(`Configured queues: ${output.count || 0}`);
241
+ console.log('');
242
+ for (let i = 0; i < output.queues.length; i += 1) {
243
+ const row = output.queues[i];
244
+ const marker = row.isDefault ? ' (default)' : '';
245
+ const team = row.team ? ` [${row.team}]` : '';
246
+ console.log(`${i + 1}. ${row.alias}${marker}${team}`);
247
+ console.log(` ${row.path || '(no path configured)'}`);
248
+ }
249
+ return;
250
+ }
251
+ if (output.command === 'auth-check') {
252
+ console.log(`CDP: ${output.cdp.reachable ? 'reachable' : 'unreachable'}`);
253
+ console.log(`Config: ${output.config.ok ? 'valid' : 'invalid'}`);
254
+ console.log(`Auth: ${output.auth.authenticated ? 'authenticated' : 'not authenticated'}`);
255
+ if (output.auth.user) {
256
+ console.log(`User: ${output.auth.user.name || output.auth.user.email || output.auth.user.id}`);
257
+ }
258
+ if (output.persisted) {
259
+ console.log(`Stored: ${output.persisted.latestPath}`);
260
+ }
261
+ if (!output.config.ok && Array.isArray(output.config.issues) && output.config.issues.length) {
262
+ console.log('');
263
+ for (const issue of output.config.issues) {
264
+ console.log(`- ${issue}`);
265
+ }
266
+ }
267
+ return;
268
+ }
269
+ if (output.command === 'auth-login') {
270
+ console.log(output.authenticated ? 'Zendesk login confirmed.' : 'Zendesk login not confirmed.');
271
+ console.log(`URL: ${output.pageUrl || output.startUrl || 'unknown'}`);
272
+ if (output.user) {
273
+ console.log(`User: ${output.user.name || output.user.email || output.user.id}`);
274
+ }
275
+ if (output.persisted) {
276
+ console.log(`Stored: ${output.persisted.latestPath}`);
277
+ }
278
+ return;
279
+ }
280
+ if (output.command === 'doctor') {
281
+ console.log(`Status: ${output.ok ? 'ok' : 'needs attention'}`);
282
+ for (const check of output.checks || []) {
283
+ console.log(`- ${check.name}: ${check.ok ? 'ok' : 'fail'}${check.detail ? ` (${check.detail})` : ''}`);
284
+ }
285
+ if (output.persisted) {
286
+ console.log(`Stored: ${output.persisted.latestPath}`);
287
+ }
288
+ }
289
+ }
290
+ async function withZendeskBrowser(program, handler) {
291
+ const globalOpts = resolveGlobalOpts(program);
292
+ if (!globalOpts.domain) {
293
+ throw new Error('Zendesk domain is required. Set `domain` in zendesk config, `ZENDESK_DOMAIN`, or pass `--domain`.');
294
+ }
295
+ const cdp = await (0, browser_cdp_1.ensureCdp)({
296
+ cdpUrl: globalOpts.cdpUrl,
297
+ profileDir: globalOpts.profileDir,
298
+ noLaunch: globalOpts.noLaunch,
299
+ allowSharedCdp: globalOpts.allowSharedCdp,
300
+ autoPort: globalOpts.autoPort,
301
+ cdpPortSpan: globalOpts.cdpPortSpan
302
+ });
303
+ const browser = await playwright_1.chromium.connectOverCDP(cdp.wsEndpoint);
304
+ try {
305
+ const context = browser.contexts()[0];
306
+ if (!context) {
307
+ throw new Error('No browser context available from CDP connection.');
308
+ }
309
+ const page = await (0, automation_1.getZendeskPage)(context, globalOpts.startUrl, globalOpts.background);
310
+ await (0, browser_cdp_1.prepareInteractionContext)(page, globalOpts.uiWaitMs);
311
+ return await handler({ page, globalOpts, cdp });
312
+ }
313
+ finally {
314
+ await browser.close();
315
+ }
316
+ }
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.persistOutput = persistOutput;
7
+ exports.readCachedTicket = readCachedTicket;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const util_1 = require("./util");
11
+ function nowParts(now = new Date()) {
12
+ const yyyy = String(now.getFullYear());
13
+ const mm = String(now.getMonth() + 1).padStart(2, '0');
14
+ const dd = String(now.getDate()).padStart(2, '0');
15
+ const hh = String(now.getHours()).padStart(2, '0');
16
+ const mi = String(now.getMinutes()).padStart(2, '0');
17
+ const ss = String(now.getSeconds()).padStart(2, '0');
18
+ return { yyyy, mm, dd, hh, mi, ss };
19
+ }
20
+ function persistOutput(result, globalOpts) {
21
+ if (!globalOpts.store || !result || !result.command) {
22
+ return null;
23
+ }
24
+ const now = new Date();
25
+ const { yyyy, mm, dd, hh, mi, ss } = nowParts(now);
26
+ const root = globalOpts.storeRoot;
27
+ if (result.command === 'read-ticket') {
28
+ const ticketId = result.ticketId || (0, util_1.parseTicketIdFromUrl)(result.pageUrl || '') || 'unknown';
29
+ const ticketRoot = path_1.default.join(root, 'tickets', String(ticketId));
30
+ const snapshotPath = path_1.default.join(ticketRoot, 'snapshots', yyyy, mm, dd, `${hh}${mi}${ss}.json`);
31
+ const latestPath = path_1.default.join(ticketRoot, 'latest.json');
32
+ const record = {
33
+ capturedAt: now.toISOString(),
34
+ ...result
35
+ };
36
+ (0, util_1.writeJson)(snapshotPath, record);
37
+ (0, util_1.writeJson)(latestPath, record);
38
+ return {
39
+ entity: 'ticket',
40
+ ticketId: String(ticketId),
41
+ ticketRoot,
42
+ latestPath,
43
+ snapshotPath
44
+ };
45
+ }
46
+ if (result.command === 'read-queue') {
47
+ const slug = (0, util_1.slugify)(result.queueName || 'queue');
48
+ const queueRoot = path_1.default.join(root, 'queues', slug);
49
+ const snapshotPath = path_1.default.join(queueRoot, 'snapshots', yyyy, mm, dd, `${hh}${mi}${ss}.json`);
50
+ const latestPath = path_1.default.join(queueRoot, 'latest.json');
51
+ const record = {
52
+ capturedAt: now.toISOString(),
53
+ ...result
54
+ };
55
+ (0, util_1.writeJson)(snapshotPath, record);
56
+ (0, util_1.writeJson)(latestPath, record);
57
+ return {
58
+ entity: 'queue',
59
+ queue: slug,
60
+ queueRoot,
61
+ latestPath,
62
+ snapshotPath
63
+ };
64
+ }
65
+ if (result.command === 'search-tickets') {
66
+ const slug = (0, util_1.slugify)(result.query || 'query');
67
+ const searchRoot = path_1.default.join(root, 'searches', slug);
68
+ const snapshotPath = path_1.default.join(searchRoot, yyyy, mm, dd, `${hh}${mi}${ss}.json`);
69
+ const latestPath = path_1.default.join(searchRoot, 'latest.json');
70
+ const record = {
71
+ capturedAt: now.toISOString(),
72
+ ...result
73
+ };
74
+ (0, util_1.writeJson)(snapshotPath, record);
75
+ (0, util_1.writeJson)(latestPath, record);
76
+ return {
77
+ entity: 'search',
78
+ query: slug,
79
+ searchRoot,
80
+ latestPath,
81
+ snapshotPath
82
+ };
83
+ }
84
+ return null;
85
+ }
86
+ function readCachedTicket({ storeRoot, ticketId, ttlSeconds = 120 }) {
87
+ const id = String(ticketId || '').replace(/\D+/g, '');
88
+ if (!storeRoot || !id) {
89
+ return null;
90
+ }
91
+ const latestPath = path_1.default.join(storeRoot, 'tickets', id, 'latest.json');
92
+ if (!fs_1.default.existsSync(latestPath)) {
93
+ return null;
94
+ }
95
+ const payload = (0, util_1.readJson)(latestPath, null);
96
+ if (!payload || payload.command !== 'read-ticket') {
97
+ return null;
98
+ }
99
+ const capturedAtMs = Date.parse(payload.capturedAt || '');
100
+ if (!Number.isFinite(capturedAtMs)) {
101
+ return null;
102
+ }
103
+ const ageSeconds = Math.max(0, Math.floor((Date.now() - capturedAtMs) / 1000));
104
+ const ttl = Math.max(0, Number(ttlSeconds) || 0);
105
+ if (ttl > 0 && ageSeconds > ttl) {
106
+ return null;
107
+ }
108
+ return {
109
+ ...payload,
110
+ cacheHit: true,
111
+ cacheAgeSeconds: ageSeconds,
112
+ cachePath: latestPath
113
+ };
114
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sleep = sleep;
7
+ exports.clean = clean;
8
+ exports.slugify = slugify;
9
+ exports.readJson = readJson;
10
+ exports.writeJson = writeJson;
11
+ exports.parseTicketIdFromUrl = parseTicketIdFromUrl;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ function sleep(ms) {
15
+ return new Promise((resolve) => setTimeout(resolve, ms));
16
+ }
17
+ function clean(text) {
18
+ return (text || '').replace(/\s+/g, ' ').trim();
19
+ }
20
+ function slugify(value) {
21
+ return clean(value)
22
+ .toLowerCase()
23
+ .replace(/[^a-z0-9]+/g, '-')
24
+ .replace(/(^-|-$)/g, '') || 'unknown';
25
+ }
26
+ function readJson(filePath, fallback = {}) {
27
+ try {
28
+ const raw = fs_1.default.readFileSync(filePath, 'utf8');
29
+ return JSON.parse(raw);
30
+ }
31
+ catch (_) {
32
+ return fallback;
33
+ }
34
+ }
35
+ function writeJson(filePath, data) {
36
+ fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
37
+ fs_1.default.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
38
+ }
39
+ function parseTicketIdFromUrl(pageUrl = '') {
40
+ const m = String(pageUrl).match(/\/agent\/tickets\/(\d+)/i);
41
+ return m ? m[1] : null;
42
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "zd-agent-cli",
3
+ "version": "0.1.1",
4
+ "description": "AI Agent ready Zendesk access through your existing browser session. No API keys required.",
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "bin": {
8
+ "zagent": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE",
14
+ "zendesk.config.example.json"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/roger-rodriguez/zd-agent-cli.git"
22
+ },
23
+ "homepage": "https://github.com/roger-rodriguez/zd-agent-cli#readme",
24
+ "bugs": {
25
+ "url": "https://github.com/roger-rodriguez/zd-agent-cli/issues"
26
+ },
27
+ "keywords": [
28
+ "zendesk",
29
+ "cli",
30
+ "playwright",
31
+ "cdp"
32
+ ],
33
+ "scripts": {
34
+ "cli": "tsx src/cli.ts",
35
+ "dev": "tsx src/cli.ts",
36
+ "typecheck": "tsc --noEmit",
37
+ "build": "rm -rf dist && tsc -p tsconfig.json",
38
+ "prepack": "npm run build",
39
+ "lint": "eslint src test scripts",
40
+ "test": "node --test",
41
+ "smoke": "node scripts/smoke.cjs",
42
+ "verify": "npm run lint && npm run typecheck && npm run build && npm run test && npm run smoke"
43
+ },
44
+ "dependencies": {
45
+ "commander": "^14.0.3",
46
+ "get-port": "^7.1.0",
47
+ "playwright": "^1.58.2"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^25.3.2",
51
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
52
+ "@typescript-eslint/parser": "^8.56.1",
53
+ "eslint": "^10.0.2",
54
+ "tsx": "^4.21.0",
55
+ "typescript": "^5.9.3"
56
+ }
57
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "domain": "acme.zendesk.com",
3
+ "cdpUrl": "http://127.0.0.1:9223",
4
+ "cdpPortSpan": 10,
5
+ "allowSharedCdp": false,
6
+ "noAutoPort": false,
7
+ "profileDir": "./output/zendesk/chrome-profile",
8
+ "startPath": "/agent/filters/123456789",
9
+ "storeRoot": "./output/zendesk",
10
+ "cacheTtl": 120,
11
+ "cacheOnly": false,
12
+ "noCache": false,
13
+ "defaultQueue": "support",
14
+ "queues": {
15
+ "support": {
16
+ "path": "/agent/filters/123456789",
17
+ "team": "support"
18
+ },
19
+ "billing": {
20
+ "path": "/agent/filters/987654321",
21
+ "team": "billing"
22
+ }
23
+ },
24
+ "uiWaitMs": 1200,
25
+ "noLaunch": false,
26
+ "foreground": false,
27
+ "noStore": false
28
+ }