autokap 1.6.1 → 1.6.3
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/browser-pool.d.ts +1 -0
- package/dist/browser-pool.js +2 -0
- package/dist/browser.js +13 -1
- package/dist/cli-config.js +69 -25
- package/dist/cli-contract.d.ts +25 -5
- package/dist/cli-contract.js +55 -151
- package/dist/cli-doctor.d.ts +1 -1
- package/dist/cli-doctor.js +67 -82
- package/dist/cli-runner.d.ts +1 -1
- package/dist/cli-runner.js +23 -10
- package/dist/cli.js +25 -1163
- package/dist/execution-schema.d.ts +9 -3
- package/dist/execution-schema.js +12 -0
- package/dist/execution-types.d.ts +33 -2
- package/dist/mockup.d.ts +66 -2
- package/dist/mockup.js +31 -14
- package/dist/opcode-runner.js +9 -0
- package/dist/program-signing.d.ts +4 -1
- package/dist/program-signing.js +4 -0
- package/dist/skill-packaging.d.ts +0 -16
- package/dist/skill-packaging.js +1 -51
- package/dist/transform-browser-url.d.ts +6 -0
- package/dist/transform-browser-url.js +28 -0
- package/dist/types.d.ts +11 -0
- package/dist/video-narration-schema.d.ts +4 -1
- package/dist/web-playwright-local.d.ts +1 -0
- package/dist/web-playwright-local.js +0 -0
- package/package.json +6 -6
- package/readme.md +15 -12
- package/assets/skill/OPCODE-REFERENCE.md +0 -625
- package/assets/skill/README.md +0 -38
- package/assets/skill/SKILL.md +0 -590
- package/assets/skill/references/STANDARDS.md +0 -236
- package/assets/skill/references/examples.md +0 -88
- package/assets/skill/references/mock-data.md +0 -178
- package/dist/auth-capture.d.ts +0 -17
- package/dist/auth-capture.js +0 -199
- package/dist/cli-utils.d.ts +0 -5
- package/dist/cli-utils.js +0 -14
- package/dist/version-check.d.ts +0 -4
- package/dist/version-check.js +0 -102
package/dist/cli-doctor.js
CHANGED
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
3
|
import chalk from 'chalk';
|
|
5
4
|
import { chromium } from 'playwright';
|
|
6
5
|
import { logger } from './logger.js';
|
|
7
6
|
import { ensureFfmpegAvailable } from './clip-postprocess.js';
|
|
8
7
|
import { readConfig, getConfigPath } from './cli-config.js';
|
|
9
|
-
import { getCachedOrFetchLatest, isNewerVersion } from './version-check.js';
|
|
10
|
-
import { writeSkillExport } from './skill-packaging.js';
|
|
11
8
|
const REQUIRED_NODE_MAJOR = 20;
|
|
12
|
-
const AGENT_PATHS = {
|
|
13
|
-
claude: '.claude/commands/autokap-preset.md',
|
|
14
|
-
codex: '.agents/skills/autokap-preset/SKILL.md',
|
|
15
|
-
cursor: '.cursor/rules/autokap-preset.md',
|
|
16
|
-
windsurf: '.windsurf/rules/autokap-preset.md',
|
|
17
|
-
copilot: '.github/instructions/autokap-preset.instructions.md',
|
|
18
|
-
};
|
|
19
9
|
async function pathExists(candidate) {
|
|
20
10
|
try {
|
|
21
11
|
await fs.access(candidate);
|
|
@@ -108,7 +98,7 @@ async function checkConfig() {
|
|
|
108
98
|
name: 'CLI configuration',
|
|
109
99
|
status: 'fail',
|
|
110
100
|
message: `Failed to read config: ${err.message}`,
|
|
111
|
-
fixCommand: 'autokap
|
|
101
|
+
fixCommand: 'autokap login <key> # or call autokap_authenticate via your MCP-enabled IDE',
|
|
112
102
|
};
|
|
113
103
|
}
|
|
114
104
|
if (!config) {
|
|
@@ -116,7 +106,7 @@ async function checkConfig() {
|
|
|
116
106
|
name: 'CLI configuration',
|
|
117
107
|
status: 'fail',
|
|
118
108
|
message: `No API key found. Checked AUTOKAP_RUN_TOKEN, AUTOKAP_API_KEY, and ${getConfigPath()}.`,
|
|
119
|
-
fixCommand: 'autokap
|
|
109
|
+
fixCommand: 'autokap login <key> # or call autokap_authenticate via your MCP-enabled IDE',
|
|
120
110
|
};
|
|
121
111
|
}
|
|
122
112
|
if (!config.apiKey) {
|
|
@@ -124,7 +114,7 @@ async function checkConfig() {
|
|
|
124
114
|
name: 'CLI configuration',
|
|
125
115
|
status: 'fail',
|
|
126
116
|
message: 'Config exists but apiKey is empty.',
|
|
127
|
-
fixCommand: 'autokap
|
|
117
|
+
fixCommand: 'autokap login <key>',
|
|
128
118
|
};
|
|
129
119
|
}
|
|
130
120
|
return {
|
|
@@ -133,76 +123,55 @@ async function checkConfig() {
|
|
|
133
123
|
message: `apiBaseUrl=${config.apiBaseUrl}`,
|
|
134
124
|
};
|
|
135
125
|
}
|
|
136
|
-
async function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
['.cursor', 'cursor'],
|
|
141
|
-
['.windsurf', 'windsurf'],
|
|
142
|
-
['.github/instructions', 'copilot'],
|
|
143
|
-
];
|
|
144
|
-
for (const [dir, key] of detectors) {
|
|
145
|
-
if (await pathExists(path.join(process.cwd(), dir))) {
|
|
146
|
-
return key;
|
|
147
|
-
}
|
|
126
|
+
async function checkCliKeyValid() {
|
|
127
|
+
let config = null;
|
|
128
|
+
try {
|
|
129
|
+
config = await readConfig();
|
|
148
130
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async function checkSkill(agentOverride) {
|
|
152
|
-
const agent = agentOverride ?? (await detectAgent());
|
|
153
|
-
if (!agent) {
|
|
154
|
-
return {
|
|
155
|
-
name: 'AI agent skill',
|
|
156
|
-
status: 'warn',
|
|
157
|
-
message: 'No agent directory detected (.claude, .agents, .cursor, .windsurf, .github/instructions). Skipping skill check.',
|
|
158
|
-
fixCommand: 'autokap init # or autokap skill --agent <name> to install',
|
|
159
|
-
};
|
|
131
|
+
catch {
|
|
132
|
+
config = null;
|
|
160
133
|
}
|
|
161
|
-
|
|
162
|
-
if (await pathExists(skillPath)) {
|
|
134
|
+
if (!config || !config.apiKey) {
|
|
163
135
|
return {
|
|
164
|
-
name: '
|
|
165
|
-
status: '
|
|
166
|
-
message:
|
|
136
|
+
name: 'API key valid',
|
|
137
|
+
status: 'warn',
|
|
138
|
+
message: 'No API key configured locally — skipping remote validation.',
|
|
139
|
+
fixCommand: 'autokap login <key> # or call autokap_authenticate via your MCP-enabled IDE',
|
|
167
140
|
};
|
|
168
141
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
142
|
+
try {
|
|
143
|
+
const res = await fetch(`${config.apiBaseUrl}/api/cli/validate`, {
|
|
144
|
+
headers: { Authorization: `Bearer ${config.apiKey}` },
|
|
145
|
+
signal: AbortSignal.timeout(15_000),
|
|
146
|
+
});
|
|
147
|
+
if (res.ok) {
|
|
148
|
+
return {
|
|
149
|
+
name: 'API key valid',
|
|
150
|
+
status: 'ok',
|
|
151
|
+
message: `Key validated against ${config.apiBaseUrl}.`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (res.status === 401 || res.status === 403) {
|
|
155
|
+
return {
|
|
156
|
+
name: 'API key valid',
|
|
157
|
+
status: 'fail',
|
|
158
|
+
message: `Server rejected the API key (HTTP ${res.status}). It was likely revoked or rotated.`,
|
|
159
|
+
fixCommand: 'autokap login <new-key>',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
187
162
|
return {
|
|
188
|
-
name: '
|
|
163
|
+
name: 'API key valid',
|
|
189
164
|
status: 'warn',
|
|
190
|
-
message:
|
|
165
|
+
message: `Validation endpoint returned HTTP ${res.status}.`,
|
|
191
166
|
};
|
|
192
167
|
}
|
|
193
|
-
|
|
168
|
+
catch (err) {
|
|
194
169
|
return {
|
|
195
|
-
name: '
|
|
170
|
+
name: 'API key valid',
|
|
196
171
|
status: 'warn',
|
|
197
|
-
message:
|
|
198
|
-
fixCommand: 'npm install -g autokap@latest',
|
|
172
|
+
message: `Cannot reach validation endpoint: ${err.message}`,
|
|
199
173
|
};
|
|
200
174
|
}
|
|
201
|
-
return {
|
|
202
|
-
name: 'CLI version',
|
|
203
|
-
status: 'ok',
|
|
204
|
-
message: `${currentVersion} (latest)`,
|
|
205
|
-
};
|
|
206
175
|
}
|
|
207
176
|
function runCommandStreaming(command, args) {
|
|
208
177
|
return new Promise((resolve, reject) => {
|
|
@@ -247,28 +216,44 @@ function printCheck(result) {
|
|
|
247
216
|
}
|
|
248
217
|
console.log('');
|
|
249
218
|
}
|
|
219
|
+
function buildJsonReport(results, currentVersion) {
|
|
220
|
+
const ok = results.filter(r => r.status === 'ok').length;
|
|
221
|
+
const warn = results.filter(r => r.status === 'warn').length;
|
|
222
|
+
const fail = results.filter(r => r.status === 'fail').length;
|
|
223
|
+
return {
|
|
224
|
+
cli_version: currentVersion,
|
|
225
|
+
checks: results.map(r => ({
|
|
226
|
+
name: r.name,
|
|
227
|
+
status: r.status,
|
|
228
|
+
message: r.message,
|
|
229
|
+
fixable: Boolean(r.fixFn),
|
|
230
|
+
fix_command: r.fixCommand ?? null,
|
|
231
|
+
})),
|
|
232
|
+
summary: { ok, warn, fail, all_ok: fail === 0 && warn === 0 },
|
|
233
|
+
};
|
|
234
|
+
}
|
|
250
235
|
export async function runDoctor(opts, currentVersion) {
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
logger.error(`Unknown agent "${opts.agent}". Supported: ${Object.keys(AGENT_PATHS).join(', ')}`);
|
|
256
|
-
process.exit(1);
|
|
236
|
+
const jsonMode = Boolean(opts.json);
|
|
237
|
+
if (!jsonMode) {
|
|
238
|
+
console.log(chalk.bold('\nautokap doctor'));
|
|
239
|
+
console.log(chalk.gray(`Checking environment for autokap ${currentVersion}...\n`));
|
|
257
240
|
}
|
|
258
|
-
console.log(chalk.bold('\nautokap doctor'));
|
|
259
|
-
console.log(chalk.gray(`Checking environment for autokap ${currentVersion}...\n`));
|
|
260
241
|
const results = [];
|
|
261
242
|
results.push(checkNodeVersion());
|
|
262
243
|
results.push(await checkChromium());
|
|
263
244
|
results.push(await checkFfmpeg());
|
|
264
245
|
results.push(await checkConfig());
|
|
265
|
-
results.push(await
|
|
266
|
-
results.
|
|
246
|
+
results.push(await checkCliKeyValid());
|
|
247
|
+
const failures = results.filter(r => r.status === 'fail');
|
|
248
|
+
const warnings = results.filter(r => r.status === 'warn');
|
|
249
|
+
if (jsonMode) {
|
|
250
|
+
const report = buildJsonReport(results, currentVersion);
|
|
251
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
252
|
+
process.exit(failures.length > 0 ? 1 : 0);
|
|
253
|
+
}
|
|
267
254
|
for (const r of results) {
|
|
268
255
|
printCheck(r);
|
|
269
256
|
}
|
|
270
|
-
const failures = results.filter(r => r.status === 'fail');
|
|
271
|
-
const warnings = results.filter(r => r.status === 'warn');
|
|
272
257
|
if (opts.fix) {
|
|
273
258
|
const fixable = results.filter(r => r.status !== 'ok' && r.fixFn);
|
|
274
259
|
if (fixable.length === 0) {
|
package/dist/cli-runner.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Entry point for deterministic execution from the CLI.
|
|
5
5
|
* Flow:
|
|
6
|
-
* 1. Authenticate via stored
|
|
6
|
+
* 1. Authenticate via stored API key
|
|
7
7
|
* 2. Fetch compiled program from server
|
|
8
8
|
* 3. Validate program against Zod schema
|
|
9
9
|
* 4. Launch local Playwright browser per variant
|
package/dist/cli-runner.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Entry point for deterministic execution from the CLI.
|
|
5
5
|
* Flow:
|
|
6
|
-
* 1. Authenticate via stored
|
|
6
|
+
* 1. Authenticate via stored API key
|
|
7
7
|
* 2. Fetch compiled program from server
|
|
8
8
|
* 3. Validate program against Zod schema
|
|
9
9
|
* 4. Launch local Playwright browser per variant
|
|
@@ -25,7 +25,8 @@ import { parseProgram } from './execution-schema.js';
|
|
|
25
25
|
import { buildCursorOverlayScript } from './cursor-overlay-script.js';
|
|
26
26
|
import { CLI_VERSION_HEADER, } from './cli-contract.js';
|
|
27
27
|
import { postProcessClipRecording } from './clip-postprocess.js';
|
|
28
|
-
import { applyDeviceFrame } from './mockup.js';
|
|
28
|
+
import { applyDeviceFrame, seedDeviceConfigs } from './mockup.js';
|
|
29
|
+
import { transformBrowserUrl } from './transform-browser-url.js';
|
|
29
30
|
import { localizeStatusBar } from './status-bar-l10n.js';
|
|
30
31
|
import { logger } from './logger.js';
|
|
31
32
|
import { callLLM } from './llm-provider.js';
|
|
@@ -166,6 +167,11 @@ export async function runCapture(options) {
|
|
|
166
167
|
presetId: options.presetId,
|
|
167
168
|
};
|
|
168
169
|
}
|
|
170
|
+
// Custom device frames live in Supabase (table `device_mockups`) and the
|
|
171
|
+
// end-user CLI does not have the service role key. The server pre-fetches
|
|
172
|
+
// every device referenced by `variants[].deviceFrame` and embeds the rows
|
|
173
|
+
// here; we seed mockup.ts so the export pipeline can apply them locally.
|
|
174
|
+
seedDeviceConfigs(program.deviceConfigs ?? null);
|
|
169
175
|
const runId = randomUUID();
|
|
170
176
|
let videoAudioAssets;
|
|
171
177
|
let videoAudioAssetsByLocale;
|
|
@@ -248,6 +254,7 @@ export async function runCapture(options) {
|
|
|
248
254
|
lang: variant.locale,
|
|
249
255
|
colorScheme: variant.theme,
|
|
250
256
|
storageState: program.preconditions.storageState,
|
|
257
|
+
extraHttpHeaders: program.environmentHttpHeaders,
|
|
251
258
|
};
|
|
252
259
|
let recordingDir;
|
|
253
260
|
let browser;
|
|
@@ -884,6 +891,9 @@ async function uploadArtifactMultipart(config, program, runId, job, filename) {
|
|
|
884
891
|
formData.append('mimeType', artifact.mimeType);
|
|
885
892
|
formData.append('captureType', artifact.captureType ?? 'fullpage');
|
|
886
893
|
formData.append('captureUrl', artifact.captureUrl ?? program.baseUrl);
|
|
894
|
+
if (artifact.pageTitle) {
|
|
895
|
+
formData.append('pageTitle', artifact.pageTitle);
|
|
896
|
+
}
|
|
887
897
|
formData.append('lang', variantSpec?.locale ?? 'en');
|
|
888
898
|
formData.append('theme', variantSpec?.theme ?? 'light');
|
|
889
899
|
if (variantSpec?.deviceFrame) {
|
|
@@ -961,6 +971,7 @@ async function prepareDirectArtifactUpload(params) {
|
|
|
961
971
|
mimeType: artifact.mimeType,
|
|
962
972
|
captureType: artifact.captureType ?? 'fullpage',
|
|
963
973
|
captureUrl: artifact.captureUrl ?? program.baseUrl,
|
|
974
|
+
pageTitle: artifact.pageTitle ?? null,
|
|
964
975
|
lang: variantSpec?.locale ?? 'en',
|
|
965
976
|
theme: variantSpec?.theme ?? 'light',
|
|
966
977
|
deviceFrame: variantSpec?.deviceFrame ?? null,
|
|
@@ -1039,7 +1050,7 @@ async function prepareScreenshotBufferForDirectUpload(input, metadata, program,
|
|
|
1039
1050
|
?? 2,
|
|
1040
1051
|
showStatusBar: artifactPlan.applyStatusBar ?? false,
|
|
1041
1052
|
statusBar: localizeStatusBar({}, metadata.lang),
|
|
1042
|
-
browserBar: buildCliBrowserBar(metadata.captureUrl, metadata.theme, tabIcon),
|
|
1053
|
+
browserBar: buildCliBrowserBar(metadata.captureUrl, metadata.theme, tabIcon, { publicUrl: program.publicUrl, pageTitle: metadata.pageTitle ?? null }),
|
|
1043
1054
|
});
|
|
1044
1055
|
}
|
|
1045
1056
|
if (artifactPlan?.format?.screenshotFormat === 'jpeg') {
|
|
@@ -1122,14 +1133,16 @@ function normalizeCliDeviceScaleFactor(value) {
|
|
|
1122
1133
|
return null;
|
|
1123
1134
|
return Math.max(0.5, Math.min(4, Number(value)));
|
|
1124
1135
|
}
|
|
1125
|
-
function buildCliBrowserBar(captureUrl, colorScheme, tabIcon) {
|
|
1136
|
+
function buildCliBrowserBar(captureUrl, colorScheme, tabIcon, options = {}) {
|
|
1126
1137
|
if (!captureUrl)
|
|
1127
1138
|
return undefined;
|
|
1139
|
+
const displayUrl = transformBrowserUrl(captureUrl, options.publicUrl);
|
|
1140
|
+
const explicitTitle = options.pageTitle?.trim() || null;
|
|
1128
1141
|
try {
|
|
1129
|
-
const parsed = new URL(
|
|
1142
|
+
const parsed = new URL(displayUrl);
|
|
1130
1143
|
return {
|
|
1131
|
-
url:
|
|
1132
|
-
pageTitle: parsed.hostname,
|
|
1144
|
+
url: displayUrl,
|
|
1145
|
+
pageTitle: explicitTitle ?? parsed.hostname,
|
|
1133
1146
|
colorScheme,
|
|
1134
1147
|
tabIconUrl: tabIcon
|
|
1135
1148
|
? `data:${tabIcon.mimeType};base64,${tabIcon.buffer.toString('base64')}`
|
|
@@ -1138,8 +1151,8 @@ function buildCliBrowserBar(captureUrl, colorScheme, tabIcon) {
|
|
|
1138
1151
|
}
|
|
1139
1152
|
catch {
|
|
1140
1153
|
return {
|
|
1141
|
-
url:
|
|
1142
|
-
pageTitle:
|
|
1154
|
+
url: displayUrl,
|
|
1155
|
+
pageTitle: explicitTitle ?? displayUrl,
|
|
1143
1156
|
colorScheme,
|
|
1144
1157
|
...(tabIcon
|
|
1145
1158
|
? { tabIconUrl: `data:${tabIcon.mimeType};base64,${tabIcon.buffer.toString('base64')}` }
|
|
@@ -1230,7 +1243,7 @@ async function formatServerError(response, requestedUrl) {
|
|
|
1230
1243
|
`server returned 404 for ${requestedUrl}.`,
|
|
1231
1244
|
`The configured AutoKap server (${safeOrigin(requestedUrl)}) does not expose this CLI route yet.`,
|
|
1232
1245
|
'This usually means the web app deployment is older than the CLI.',
|
|
1233
|
-
`Point the CLI at your local dev server with \`autokap run --local <preset-id>\`, \`${API_BASE_URL_ENV_VAR}=http://localhost:3000 autokap run <preset-id>\`, or re-
|
|
1246
|
+
`Point the CLI at your local dev server with \`autokap run --local <preset-id>\`, \`${API_BASE_URL_ENV_VAR}=http://localhost:3000 autokap run <preset-id>\`, or re-authenticate via your IDE's MCP integration (autokap_authenticate). From CI, set \`${API_BASE_URL_ENV_VAR}=http://localhost:3000\` and run \`autokap login <key>\`.`,
|
|
1234
1247
|
].join(' ');
|
|
1235
1248
|
}
|
|
1236
1249
|
if (isHtml) {
|