autokap 1.2.0 → 1.3.2
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/assets/skill/OPCODE-REFERENCE.md +18 -1
- package/assets/skill/SKILL.md +54 -11
- package/dist/browser.js +23 -1
- package/dist/capture-strategy.d.ts +14 -0
- package/dist/capture-strategy.js +28 -0
- package/dist/cli-contract.d.ts +61 -0
- package/dist/cli-runner.d.ts +10 -1
- package/dist/cli-runner.js +415 -20
- package/dist/cli.js +124 -2
- package/dist/clip-capture-loop.js +11 -2
- package/dist/cookie-dismiss.d.ts +1 -0
- package/dist/cookie-dismiss.js +13 -1
- package/dist/execution-schema.d.ts +303 -2
- package/dist/execution-schema.js +77 -4
- package/dist/execution-types.d.ts +114 -5
- package/dist/execution-types.js +2 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -0
- package/dist/mouse-animation.d.ts +12 -2
- package/dist/mouse-animation.js +36 -6
- package/dist/opcode-actions.d.ts +2 -0
- package/dist/opcode-actions.js +39 -5
- package/dist/opcode-runner.d.ts +2 -0
- package/dist/opcode-runner.js +139 -17
- package/dist/openrouter-tts.d.ts +74 -0
- package/dist/openrouter-tts.js +218 -0
- package/dist/postcondition.js +36 -26
- package/dist/program-signing.d.ts +67 -0
- package/dist/recovery-chain.js +26 -12
- package/dist/server-credit-usage.d.ts +1 -1
- package/dist/video-narration-schema.d.ts +1165 -0
- package/dist/video-narration-schema.js +137 -0
- package/dist/web-playwright-local.d.ts +16 -0
- package/dist/web-playwright-local.js +204 -18
- package/package.json +9 -1
package/dist/cli.js
CHANGED
|
@@ -240,21 +240,58 @@ program
|
|
|
240
240
|
.option('--local', `Use the local AutoKap dev server (${LOCAL_API_BASE_URL})`, false)
|
|
241
241
|
.option('--allow-upload-failure', 'Keep a successful capture exit code even if artifact upload fails', false)
|
|
242
242
|
.option('--debug', 'Verbose logging: per-substep timing, opcode dumps, recovery strategy traces', false)
|
|
243
|
+
.option('--cloud', 'Cloud runner mode: signals 4+ vCPU available, unblocks the conservative Linux FPS default (8 → 30)', false)
|
|
243
244
|
.action(async (opts) => {
|
|
244
245
|
if (opts.debug) {
|
|
245
246
|
const { setDebugEnabled } = await import('./logger.js');
|
|
246
247
|
setDebugEnabled(true);
|
|
247
248
|
logger.info('[capture] Debug mode enabled — verbose logging on');
|
|
248
249
|
}
|
|
250
|
+
if (opts.cloud) {
|
|
251
|
+
process.env.AUTOKAP_CLOUD_RUNNER = '1';
|
|
252
|
+
logger.info('[capture] Cloud runner mode — Linux FPS cap lifted (clips target 30 fps)');
|
|
253
|
+
}
|
|
249
254
|
if (opts.local) {
|
|
250
255
|
process.env[API_BASE_URL_ENV_VAR] = LOCAL_API_BASE_URL;
|
|
251
256
|
process.env[WS_URL_ENV_VAR] = LOCAL_WS_URL;
|
|
252
257
|
logger.info(`Using local AutoKap dev server: ${LOCAL_API_BASE_URL}`);
|
|
253
258
|
}
|
|
254
259
|
const config = await requireConfig();
|
|
260
|
+
// AUTOKAP_RUN_ID is set by the cloud-runner provider when the CLI is
|
|
261
|
+
// launched on Fly.io. When present, we POST a completion callback at exit
|
|
262
|
+
// so the `capture_runs` row flips out of `queued` — without this the
|
|
263
|
+
// backend rate-limiter blocks future cloud recaptures.
|
|
264
|
+
const cloudRunId = process.env.AUTOKAP_RUN_ID;
|
|
265
|
+
/**
|
|
266
|
+
* Best-effort: tell the AutoKap backend whether this cloud run finished
|
|
267
|
+
* cleanly. Failures here do NOT change the CLI exit code — the artifact
|
|
268
|
+
* uploads are already done at this point, so a missed callback only
|
|
269
|
+
* affects status reporting (a reconciliation cron heals it later).
|
|
270
|
+
*/
|
|
271
|
+
const notifyCloudCallback = async (status, details) => {
|
|
272
|
+
if (!cloudRunId)
|
|
273
|
+
return;
|
|
274
|
+
try {
|
|
275
|
+
const response = await fetch(buildApiUrl(config, `/api/cli/cloud-recapture/${cloudRunId}/complete`), {
|
|
276
|
+
method: 'POST',
|
|
277
|
+
headers: { ...authHeaders(config), 'Content-Type': 'application/json' },
|
|
278
|
+
body: JSON.stringify({ status, ...details }),
|
|
279
|
+
});
|
|
280
|
+
if (!response.ok) {
|
|
281
|
+
const body = await response.text().catch(() => response.statusText);
|
|
282
|
+
logger.warn(`[auto-recapture] Cloud callback non-OK (${response.status}): ${body}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
logger.info(`[auto-recapture] Cloud run marked ${status} on backend`);
|
|
286
|
+
}
|
|
287
|
+
catch (err) {
|
|
288
|
+
logger.warn(`[auto-recapture] Cloud callback failed (best-effort): ${err.message}`);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
255
291
|
const data = await requestJson(config, `/api/cli/projects/${opts.project}/auto-recapture-presets`, { headers: authHeaders(config) }, 'Failed to list auto-recapture presets');
|
|
256
292
|
if (data.presets.length === 0) {
|
|
257
293
|
logger.info(`[auto-recapture] No presets enabled for project ${opts.project}`);
|
|
294
|
+
await notifyCloudCallback('completed', { totalPresets: 0, failedPresets: 0 });
|
|
258
295
|
process.exit(0);
|
|
259
296
|
}
|
|
260
297
|
const { runCapture } = await import('./cli-runner.js');
|
|
@@ -275,12 +312,22 @@ program
|
|
|
275
312
|
}
|
|
276
313
|
}
|
|
277
314
|
if (failures.length > 0) {
|
|
278
|
-
|
|
315
|
+
const errorMessage = `${failures.length}/${data.presets.length} preset(s) failed: ${failures
|
|
279
316
|
.map((failure) => failure.name ?? failure.id)
|
|
280
|
-
.join(', ')}
|
|
317
|
+
.join(', ')}`;
|
|
318
|
+
logger.error(`[auto-recapture] ${errorMessage}`);
|
|
319
|
+
await notifyCloudCallback('failed', {
|
|
320
|
+
totalPresets: data.presets.length,
|
|
321
|
+
failedPresets: failures.length,
|
|
322
|
+
errorMessage,
|
|
323
|
+
});
|
|
281
324
|
process.exit(1);
|
|
282
325
|
}
|
|
283
326
|
logger.success(`[auto-recapture] ${data.presets.length} preset(s) recaptured successfully`);
|
|
327
|
+
await notifyCloudCallback('completed', {
|
|
328
|
+
totalPresets: data.presets.length,
|
|
329
|
+
failedPresets: 0,
|
|
330
|
+
});
|
|
284
331
|
process.exit(0);
|
|
285
332
|
});
|
|
286
333
|
// ── project commands ───────────────────────────────────────────────
|
|
@@ -606,6 +653,81 @@ presetCmd
|
|
|
606
653
|
console.log(JSON.stringify(info, null, 2));
|
|
607
654
|
process.exit(0);
|
|
608
655
|
});
|
|
656
|
+
// ── video commands ─────────────────────────────────────────────────
|
|
657
|
+
//
|
|
658
|
+
// Mirrors the preset commands but targets `/api/video-projects` (CLI-keyed
|
|
659
|
+
// route used by the IDE skill flow). The payload file contains the full
|
|
660
|
+
// body expected by the API (projectId, title, user_script, legacy
|
|
661
|
+
// narration_voice/narration_locale aliases, narration_by_app_locale,
|
|
662
|
+
// app_locale/app_locales, app_theme/app_themes, cursor_theme,
|
|
663
|
+
// credentials_account_id, mockDataInjection, program). On `update`, the same payload shape is sent
|
|
664
|
+
// via PATCH. TTS is generated later by `autokap run`.
|
|
665
|
+
const videoCmd = program
|
|
666
|
+
.command('video')
|
|
667
|
+
.description('Manage demo videos');
|
|
668
|
+
videoCmd
|
|
669
|
+
.command('create')
|
|
670
|
+
.description('Create a new demo video from a JSON payload file')
|
|
671
|
+
.requiredOption('--payload <file>', 'Path to payload JSON file (use "-" for stdin)')
|
|
672
|
+
.action(async (opts) => {
|
|
673
|
+
const cfg = await requireConfig();
|
|
674
|
+
let payload;
|
|
675
|
+
try {
|
|
676
|
+
payload = await readJsonInput(opts.payload);
|
|
677
|
+
}
|
|
678
|
+
catch (err) {
|
|
679
|
+
logger.error(`Failed to read payload: ${err.message}`);
|
|
680
|
+
process.exit(1);
|
|
681
|
+
}
|
|
682
|
+
const res = await fetch(`${cfg.apiBaseUrl}/api/video-projects`, {
|
|
683
|
+
method: 'POST',
|
|
684
|
+
headers: {
|
|
685
|
+
Authorization: `Bearer ${cfg.apiKey}`,
|
|
686
|
+
'Content-Type': 'application/json',
|
|
687
|
+
},
|
|
688
|
+
body: JSON.stringify(payload),
|
|
689
|
+
});
|
|
690
|
+
if (!res.ok) {
|
|
691
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
692
|
+
logger.error(`Failed to create video: ${body.error || res.statusText}`);
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
695
|
+
const data = await res.json();
|
|
696
|
+
// Output only the video ID so callers can chain: autokap run $(autokap video create ...)
|
|
697
|
+
console.log(data.video.id);
|
|
698
|
+
process.exit(0);
|
|
699
|
+
});
|
|
700
|
+
videoCmd
|
|
701
|
+
.command('update <video-id>')
|
|
702
|
+
.description('Update an existing demo video from a JSON payload file')
|
|
703
|
+
.requiredOption('--payload <file>', 'Path to payload JSON file (use "-" for stdin)')
|
|
704
|
+
.action(async (videoId, opts) => {
|
|
705
|
+
const cfg = await requireConfig();
|
|
706
|
+
let payload;
|
|
707
|
+
try {
|
|
708
|
+
payload = await readJsonInput(opts.payload);
|
|
709
|
+
}
|
|
710
|
+
catch (err) {
|
|
711
|
+
logger.error(`Failed to read payload: ${err.message}`);
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
const res = await fetch(`${cfg.apiBaseUrl}/api/video-projects/${videoId}`, {
|
|
715
|
+
method: 'PATCH',
|
|
716
|
+
headers: {
|
|
717
|
+
Authorization: `Bearer ${cfg.apiKey}`,
|
|
718
|
+
'Content-Type': 'application/json',
|
|
719
|
+
},
|
|
720
|
+
body: JSON.stringify(payload),
|
|
721
|
+
});
|
|
722
|
+
if (!res.ok) {
|
|
723
|
+
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
724
|
+
logger.error(`Failed to update video: ${body.error || res.statusText}`);
|
|
725
|
+
process.exit(1);
|
|
726
|
+
}
|
|
727
|
+
const data = await res.json();
|
|
728
|
+
console.log(data.video.id);
|
|
729
|
+
process.exit(0);
|
|
730
|
+
});
|
|
609
731
|
// ── auth commands ──────────────────────────────────────────────────
|
|
610
732
|
const authCmd = program
|
|
611
733
|
.command('auth')
|
|
@@ -34,10 +34,19 @@ export class ClipCaptureLoop {
|
|
|
34
34
|
this.page = opts.page;
|
|
35
35
|
this.framesDir = opts.framesDir;
|
|
36
36
|
this.jpegQuality = opts.jpegQuality ?? 80;
|
|
37
|
-
|
|
37
|
+
// Linux default is 8 fps to stay safe on 2 vCPU CI runners. Cloud runners
|
|
38
|
+
// (AUTOKAP_CLOUD_RUNNER=1, set by the Fly.io image and the `--cloud` CLI
|
|
39
|
+
// flag) get the same 15 fps default as macOS/Windows since they have
|
|
40
|
+
// ≥ 4 vCPU. Callers can still override via opts.targetFps.
|
|
41
|
+
const isCloudRunner = process.env.AUTOKAP_CLOUD_RUNNER === '1';
|
|
42
|
+
const linuxDefault = isCloudRunner ? 15 : 8;
|
|
43
|
+
const platformDefault = process.platform === 'linux' ? linuxDefault : 15;
|
|
44
|
+
const targetFps = Math.max(1, Math.min(30, opts.targetFps ?? platformDefault));
|
|
38
45
|
this.targetFps = targetFps;
|
|
39
46
|
this.targetFrameIntervalMs = 1000 / targetFps;
|
|
40
|
-
|
|
47
|
+
const linuxMinRest = isCloudRunner ? 16 : 50;
|
|
48
|
+
const platformMinRest = process.platform === 'linux' ? linuxMinRest : 16;
|
|
49
|
+
this.minRestMs = Math.max(0, Math.min(250, opts.minRestMs ?? platformMinRest));
|
|
41
50
|
}
|
|
42
51
|
async start() {
|
|
43
52
|
this.cdp = await this.page.context().newCDPSession(this.page);
|
package/dist/cookie-dismiss.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Page } from 'playwright';
|
|
2
|
+
export declare const CAPTURE_HIDE_STYLE_ID = "autokap-capture-hide-style";
|
|
2
3
|
export declare function getCaptureHideCSS(): string;
|
|
3
4
|
export declare function ensureCaptureHideStyles(page: Page): Promise<void>;
|
|
4
5
|
export declare function dismissCookiesAndWidgets(page: Page): Promise<{
|
package/dist/cookie-dismiss.js
CHANGED
|
@@ -98,8 +98,20 @@ const DEV_TOOL_SELECTORS = [
|
|
|
98
98
|
'nuxt-devtools-frame',
|
|
99
99
|
'#nuxt-devtools-anchor',
|
|
100
100
|
'#nuxt-devtools-container',
|
|
101
|
+
// Common coding-agent / prototype builder chrome
|
|
102
|
+
'[data-testid="v0-toolbar"]',
|
|
103
|
+
'#v0-toolbar',
|
|
104
|
+
'[data-v0-devtools]',
|
|
105
|
+
'[data-lovable-badge]',
|
|
106
|
+
'#lovable-badge',
|
|
107
|
+
'[class*="lovable-badge"]',
|
|
108
|
+
'[data-bolt-toolbar]',
|
|
109
|
+
'#bolt-toolbar',
|
|
110
|
+
'[class*="bolt-toolbar"]',
|
|
111
|
+
'[data-replit-devtools]',
|
|
112
|
+
'#replit-devtools',
|
|
101
113
|
];
|
|
102
|
-
const CAPTURE_HIDE_STYLE_ID = 'autokap-capture-hide-style';
|
|
114
|
+
export const CAPTURE_HIDE_STYLE_ID = 'autokap-capture-hide-style';
|
|
103
115
|
export function getCaptureHideCSS() {
|
|
104
116
|
return [...HIDE_SELECTORS, ...DEV_TOOL_SELECTORS].map(selector => `${selector} { display: none !important; visibility: hidden !important; pointer-events: none !important; }`).join('\n');
|
|
105
117
|
}
|