autokap 1.0.10 → 1.1.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 +1 -41
- package/assets/skill/README.md +0 -1
- package/assets/skill/SKILL.md +9 -32
- package/assets/skill/references/examples.md +1 -17
- package/dist/billing-operation-logging.d.ts +2 -5
- package/dist/billing-operation-logging.js +0 -7
- package/dist/capture-strategy.d.ts +2 -8
- package/dist/capture-strategy.js +2 -30
- package/dist/cli-config.d.ts +2 -1
- package/dist/cli-config.js +18 -2
- package/dist/cli-contract.d.ts +1 -0
- package/dist/cli-contract.js +8 -2
- package/dist/cli-runner-local.d.ts +2 -0
- package/dist/cli-runner-local.js +12 -21
- package/dist/cli-runner.d.ts +4 -0
- package/dist/cli-runner.js +30 -50
- package/dist/cli.js +89 -44
- package/dist/cost-logging.d.ts +1 -1
- package/dist/execution-schema.d.ts +143 -331
- package/dist/execution-schema.js +43 -28
- package/dist/execution-types.d.ts +6 -151
- package/dist/execution-types.js +1 -3
- package/dist/logger.js +1 -1
- package/dist/mockup-html.d.ts +2 -0
- package/dist/mockup-html.js +13 -10
- package/dist/mockup.js +2 -2
- package/dist/opcode-actions.js +0 -2
- package/dist/opcode-runner.js +0 -121
- package/dist/program-signing.d.ts +50 -72
- package/dist/security.js +2 -2
- package/dist/server-capture-runtime.d.ts +0 -1
- package/dist/server-capture-runtime.js +0 -3
- package/dist/server-credit-usage.d.ts +1 -1
- package/dist/skill-packaging.d.ts +1 -1
- package/dist/skill-packaging.js +1 -11
- package/dist/types.d.ts +2 -2
- package/dist/web-playwright-local.d.ts +0 -14
- package/dist/web-playwright-local.js +0 -194
- package/package.json +1 -18
- package/readme.md +13 -0
- package/assets/skill/STUDIO-SKILL.md +0 -476
- package/assets/skill/references/interactive-demo.md +0 -225
|
@@ -42,7 +42,6 @@ const BILLING_PLANS = [
|
|
|
42
42
|
aiDailyCostLimitUsd: 0.05,
|
|
43
43
|
apiRateLimitRpm: 10,
|
|
44
44
|
maxDevLinks: 1,
|
|
45
|
-
maxCompositions: 2,
|
|
46
45
|
maxTeamMembersPerProject: null,
|
|
47
46
|
},
|
|
48
47
|
},
|
|
@@ -72,7 +71,6 @@ const BILLING_PLANS = [
|
|
|
72
71
|
aiDailyCostLimitUsd: 0.10,
|
|
73
72
|
apiRateLimitRpm: 60,
|
|
74
73
|
maxDevLinks: 10,
|
|
75
|
-
maxCompositions: 10,
|
|
76
74
|
maxTeamMembersPerProject: null,
|
|
77
75
|
},
|
|
78
76
|
},
|
|
@@ -101,7 +99,6 @@ const BILLING_PLANS = [
|
|
|
101
99
|
aiDailyCostLimitUsd: 0.15,
|
|
102
100
|
apiRateLimitRpm: 200,
|
|
103
101
|
maxDevLinks: null,
|
|
104
|
-
maxCompositions: null,
|
|
105
102
|
maxTeamMembersPerProject: 5,
|
|
106
103
|
},
|
|
107
104
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
-
export type CreditUsageType = 'screenshot' | 'clip' | '
|
|
2
|
+
export type CreditUsageType = 'screenshot' | 'clip' | 'preset_analysis' | 'ai_chat' | 'studio_creation' | 'studio_iteration';
|
|
3
3
|
export declare function recordCreditUsage(supabase: SupabaseClient, params: {
|
|
4
4
|
userId: string;
|
|
5
5
|
projectId: string | null;
|
package/dist/skill-packaging.js
CHANGED
|
@@ -17,17 +17,12 @@ const PRESET_SKILL_SOURCE = {
|
|
|
17
17
|
coreFile: 'SKILL.md',
|
|
18
18
|
references: [
|
|
19
19
|
{ relativePath: 'OPCODE-REFERENCE.md', title: 'Opcode Reference', anchor: 'reference-opcode-reference' },
|
|
20
|
-
{ relativePath: 'references/interactive-demo.md', title: 'Interactive Demo Workflow', anchor: 'reference-interactive-demo-workflow' },
|
|
21
20
|
{ relativePath: 'references/mock-data.md', title: 'Mock Data Injection', anchor: 'reference-mock-data-injection' },
|
|
22
21
|
{ relativePath: 'references/examples.md', title: 'Complete Examples', anchor: 'reference-complete-examples' },
|
|
23
22
|
],
|
|
24
23
|
};
|
|
25
|
-
const STUDIO_SKILL_SOURCE = {
|
|
26
|
-
coreFile: 'STUDIO-SKILL.md',
|
|
27
|
-
references: [],
|
|
28
|
-
};
|
|
29
24
|
function getSkillSourceSpec(type) {
|
|
30
|
-
return
|
|
25
|
+
return PRESET_SKILL_SOURCE;
|
|
31
26
|
}
|
|
32
27
|
async function pathExists(candidate) {
|
|
33
28
|
try {
|
|
@@ -75,8 +70,6 @@ function inferBundleInstall(outputPath) {
|
|
|
75
70
|
return false;
|
|
76
71
|
}
|
|
77
72
|
export function shouldInstallSkillBundle(params) {
|
|
78
|
-
if (params.type === 'studio')
|
|
79
|
-
return false;
|
|
80
73
|
if (params.agent?.toLowerCase() === 'codex')
|
|
81
74
|
return true;
|
|
82
75
|
return inferBundleInstall(params.outputPath);
|
|
@@ -113,9 +106,6 @@ export async function renderSkillSingleFile(params) {
|
|
|
113
106
|
const rootDir = await resolveSkillAssetDir();
|
|
114
107
|
const spec = getSkillSourceSpec(params.type);
|
|
115
108
|
let core = await readSkillFile(rootDir, spec.coreFile, params.placeholders);
|
|
116
|
-
if (params.type === 'studio') {
|
|
117
|
-
return core;
|
|
118
|
-
}
|
|
119
109
|
core = rewriteLinksForSingleFile(core, spec);
|
|
120
110
|
core = insertAfterFrontmatter(core, '> Packaging note: the canonical AutoKap preset skill is a modular bundle for Codex (`SKILL.md` + companion reference files). This single-file export is generated from that same source so all agents stay in parity.');
|
|
121
111
|
const bundledReferences = [];
|
package/dist/types.d.ts
CHANGED
|
@@ -583,7 +583,7 @@ export interface ClipOptions {
|
|
|
583
583
|
/** Usage metadata from a single OpenRouter API call */
|
|
584
584
|
export interface StepUsage {
|
|
585
585
|
stepNumber: number;
|
|
586
|
-
stepType: 'agent_iteration' | 'verification' | 'element_capture' | 'video_planning' | 'video_variant_classification' | 'video_step_verification' | 'video_step_fix' | 'assistant_chat' | 'mock_data_generation' | 'page_identity_classification' | 'capture_verification' | 'alt_text_generation' | 'healer_invocation';
|
|
586
|
+
stepType: 'agent_iteration' | 'verification' | 'element_capture' | 'video_planning' | 'video_variant_classification' | 'video_step_verification' | 'video_step_fix' | 'assistant_chat' | 'studio_creation' | 'studio_iteration' | 'mock_data_generation' | 'page_identity_classification' | 'capture_verification' | 'alt_text_generation' | 'healer_invocation';
|
|
587
587
|
generationId: string | null;
|
|
588
588
|
modelRequested: string;
|
|
589
589
|
modelUsed: string | null;
|
|
@@ -591,7 +591,7 @@ export interface StepUsage {
|
|
|
591
591
|
completionTokens: number | null;
|
|
592
592
|
totalTokens: number | null;
|
|
593
593
|
imagesInPrompt: number;
|
|
594
|
-
/** Prompt
|
|
594
|
+
/** Prompt assembly telemetry (optional, for cost optimization tracking) */
|
|
595
595
|
systemPromptChars?: number;
|
|
596
596
|
toolSchemaChars?: number;
|
|
597
597
|
userPayloadChars?: number;
|
|
@@ -110,20 +110,6 @@ export declare class WebPlaywrightLocal implements RuntimeAdapter {
|
|
|
110
110
|
clickHidden(opts: {
|
|
111
111
|
selector: string;
|
|
112
112
|
}): Promise<void>;
|
|
113
|
-
serializeDom(selector?: string): Promise<{
|
|
114
|
-
html: string;
|
|
115
|
-
assetUrls: string[];
|
|
116
|
-
viewport: {
|
|
117
|
-
width: number;
|
|
118
|
-
height: number;
|
|
119
|
-
};
|
|
120
|
-
capturedAt: string;
|
|
121
|
-
}>;
|
|
122
|
-
serializeFragment(selector: string): Promise<{
|
|
123
|
-
html: string;
|
|
124
|
-
assetUrls: string[];
|
|
125
|
-
capturedAt: string;
|
|
126
|
-
}>;
|
|
127
113
|
extractFavicon(): Promise<{
|
|
128
114
|
buffer: Buffer;
|
|
129
115
|
mimeType: string;
|
|
@@ -595,200 +595,6 @@ export class WebPlaywrightLocal {
|
|
|
595
595
|
el.click();
|
|
596
596
|
}, opts);
|
|
597
597
|
}
|
|
598
|
-
async serializeDom(selector) {
|
|
599
|
-
const page = await this.browser.currentPage;
|
|
600
|
-
const baseUrl = page.url();
|
|
601
|
-
const fallbackViewport = page.viewportSize() ?? { width: 1440, height: 900 };
|
|
602
|
-
const rawCapture = await page.evaluate((targetSelector) => {
|
|
603
|
-
function serializeDoctype() {
|
|
604
|
-
return document.doctype
|
|
605
|
-
? `<!DOCTYPE ${document.doctype.name}` +
|
|
606
|
-
(document.doctype.publicId ? ` PUBLIC "${document.doctype.publicId}"` : '') +
|
|
607
|
-
(document.doctype.systemId && !document.doctype.publicId ? ' SYSTEM' : '') +
|
|
608
|
-
(document.doctype.systemId ? ` "${document.doctype.systemId}"` : '') +
|
|
609
|
-
'>'
|
|
610
|
-
: '';
|
|
611
|
-
}
|
|
612
|
-
function copyAttributes(source, target) {
|
|
613
|
-
for (const attr of Array.from(source.attributes)) {
|
|
614
|
-
target.setAttribute(attr.name, attr.value);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
function buildFocusedBranch(element) {
|
|
618
|
-
let branch = element.cloneNode(true);
|
|
619
|
-
let currentSource = element.parentElement;
|
|
620
|
-
while (currentSource && currentSource !== document.body) {
|
|
621
|
-
const shell = currentSource.cloneNode(false);
|
|
622
|
-
shell.appendChild(branch);
|
|
623
|
-
branch = shell;
|
|
624
|
-
currentSource = currentSource.parentElement;
|
|
625
|
-
}
|
|
626
|
-
return branch;
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Inline same-origin <link rel="stylesheet"> tags as <style> blocks.
|
|
630
|
-
* This makes the captured HTML self-contained — CSS chunk names are
|
|
631
|
-
* build-specific and will 404 when served from a different build.
|
|
632
|
-
* Cross-origin stylesheets (e.g. Google Fonts CSS) are left as <link>
|
|
633
|
-
* tags since their URLs are stable public CDN paths.
|
|
634
|
-
*/
|
|
635
|
-
function inlineStylesheets(doc) {
|
|
636
|
-
const links = Array.from(doc.querySelectorAll('link[rel="stylesheet"]'));
|
|
637
|
-
for (const link of links) {
|
|
638
|
-
const href = link.getAttribute('href');
|
|
639
|
-
if (!href)
|
|
640
|
-
continue;
|
|
641
|
-
// Skip cross-origin stylesheets — their cssRules aren't accessible
|
|
642
|
-
// and their URLs are stable (e.g. fonts.googleapis.com).
|
|
643
|
-
try {
|
|
644
|
-
const url = new URL(href, location.origin);
|
|
645
|
-
if (url.origin !== location.origin)
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
catch {
|
|
649
|
-
continue;
|
|
650
|
-
}
|
|
651
|
-
// Find the matching CSSStyleSheet and read its rules.
|
|
652
|
-
const sheet = Array.from(doc.styleSheets).find((s) => s.ownerNode === link);
|
|
653
|
-
if (!sheet)
|
|
654
|
-
continue;
|
|
655
|
-
let cssText = '';
|
|
656
|
-
try {
|
|
657
|
-
const rules = sheet.cssRules;
|
|
658
|
-
for (let i = 0; i < rules.length; i++) {
|
|
659
|
-
cssText += rules[i].cssText + '\n';
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
catch {
|
|
663
|
-
continue;
|
|
664
|
-
} // SecurityError for cross-origin sheets
|
|
665
|
-
if (!cssText)
|
|
666
|
-
continue;
|
|
667
|
-
const style = doc.createElement('style');
|
|
668
|
-
style.textContent = cssText;
|
|
669
|
-
link.replaceWith(style);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
const doctype = serializeDoctype();
|
|
673
|
-
const root = document.documentElement;
|
|
674
|
-
if (!targetSelector) {
|
|
675
|
-
inlineStylesheets(document);
|
|
676
|
-
return {
|
|
677
|
-
html: doctype + (root ? root.outerHTML : ''),
|
|
678
|
-
viewport: {
|
|
679
|
-
width: window.innerWidth || document.documentElement.clientWidth || 1440,
|
|
680
|
-
height: window.innerHeight || document.documentElement.clientHeight || 900,
|
|
681
|
-
},
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
const element = document.querySelector(targetSelector);
|
|
685
|
-
if (!element) {
|
|
686
|
-
throw new Error(`serializeDom: no element matched selector "${targetSelector}"`);
|
|
687
|
-
}
|
|
688
|
-
if (element === document.documentElement) {
|
|
689
|
-
inlineStylesheets(document);
|
|
690
|
-
return {
|
|
691
|
-
html: doctype + root.outerHTML,
|
|
692
|
-
viewport: {
|
|
693
|
-
width: window.innerWidth || document.documentElement.clientWidth || 1440,
|
|
694
|
-
height: window.innerHeight || document.documentElement.clientHeight || 900,
|
|
695
|
-
},
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
const nextDoc = document.implementation.createHTMLDocument(document.title || '');
|
|
699
|
-
copyAttributes(document.documentElement, nextDoc.documentElement);
|
|
700
|
-
nextDoc.head.innerHTML = document.head ? document.head.innerHTML : '';
|
|
701
|
-
copyAttributes(document.body, nextDoc.body);
|
|
702
|
-
if (element === document.body) {
|
|
703
|
-
nextDoc.body.innerHTML = document.body.innerHTML;
|
|
704
|
-
}
|
|
705
|
-
else {
|
|
706
|
-
const branch = buildFocusedBranch(element);
|
|
707
|
-
nextDoc.body.replaceChildren(nextDoc.importNode(branch, true));
|
|
708
|
-
}
|
|
709
|
-
// Inline stylesheets in the cloned document. The <link> elements were
|
|
710
|
-
// copied from the live document's <head>, so their ownerNode points to
|
|
711
|
-
// the cloned <link>. The CSSStyleSheet objects on the *live* document
|
|
712
|
-
// still hold the parsed rules — iterate those and match by href.
|
|
713
|
-
const liveSheets = Array.from(document.styleSheets);
|
|
714
|
-
const clonedLinks = Array.from(nextDoc.querySelectorAll('link[rel="stylesheet"]'));
|
|
715
|
-
for (const link of clonedLinks) {
|
|
716
|
-
const href = link.getAttribute('href');
|
|
717
|
-
if (!href)
|
|
718
|
-
continue;
|
|
719
|
-
try {
|
|
720
|
-
const url = new URL(href, location.origin);
|
|
721
|
-
if (url.origin !== location.origin)
|
|
722
|
-
continue;
|
|
723
|
-
}
|
|
724
|
-
catch {
|
|
725
|
-
continue;
|
|
726
|
-
}
|
|
727
|
-
// Match by href against the live document's stylesheets.
|
|
728
|
-
const liveSheet = liveSheets.find((s) => {
|
|
729
|
-
try {
|
|
730
|
-
return s.href === new URL(href, location.origin).href;
|
|
731
|
-
}
|
|
732
|
-
catch {
|
|
733
|
-
return false;
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
if (!liveSheet)
|
|
737
|
-
continue;
|
|
738
|
-
let cssText = '';
|
|
739
|
-
try {
|
|
740
|
-
const rules = liveSheet.cssRules;
|
|
741
|
-
for (let i = 0; i < rules.length; i++) {
|
|
742
|
-
cssText += rules[i].cssText + '\n';
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
catch {
|
|
746
|
-
continue;
|
|
747
|
-
}
|
|
748
|
-
if (!cssText)
|
|
749
|
-
continue;
|
|
750
|
-
const style = nextDoc.createElement('style');
|
|
751
|
-
style.textContent = cssText;
|
|
752
|
-
link.replaceWith(style);
|
|
753
|
-
}
|
|
754
|
-
const rect = element.getBoundingClientRect();
|
|
755
|
-
return {
|
|
756
|
-
html: doctype + nextDoc.documentElement.outerHTML,
|
|
757
|
-
viewport: {
|
|
758
|
-
width: Math.max(1, Math.ceil(rect.width || window.innerWidth || document.documentElement.clientWidth || 1440)),
|
|
759
|
-
height: Math.max(1, Math.ceil(rect.height || window.innerHeight || document.documentElement.clientHeight || 900)),
|
|
760
|
-
},
|
|
761
|
-
};
|
|
762
|
-
}, selector ?? null);
|
|
763
|
-
// Lazy import to avoid loading parse5 unless DOM capture is actually used.
|
|
764
|
-
const { sanitizeDom } = await import('./dom-serializer.js');
|
|
765
|
-
const viewport = rawCapture?.viewport ?? fallbackViewport;
|
|
766
|
-
const result = sanitizeDom({ html: rawCapture.html, baseUrl, viewport });
|
|
767
|
-
return {
|
|
768
|
-
html: result.html,
|
|
769
|
-
assetUrls: result.assetUrls,
|
|
770
|
-
viewport,
|
|
771
|
-
capturedAt: new Date().toISOString(),
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
async serializeFragment(selector) {
|
|
775
|
-
const page = await this.browser.currentPage;
|
|
776
|
-
const baseUrl = page.url();
|
|
777
|
-
const rawHtml = await page.evaluate((sel) => {
|
|
778
|
-
const el = document.querySelector(sel);
|
|
779
|
-
return el ? el.outerHTML : null;
|
|
780
|
-
}, selector);
|
|
781
|
-
if (!rawHtml) {
|
|
782
|
-
throw new Error(`serializeFragment: no element matched selector "${selector}"`);
|
|
783
|
-
}
|
|
784
|
-
const { sanitizeFragment } = await import('./dom-serializer.js');
|
|
785
|
-
const result = sanitizeFragment({ html: rawHtml, baseUrl });
|
|
786
|
-
return {
|
|
787
|
-
html: result.html,
|
|
788
|
-
assetUrls: result.assetUrls,
|
|
789
|
-
capturedAt: new Date().toISOString(),
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
598
|
async extractFavicon() {
|
|
793
599
|
try {
|
|
794
600
|
const page = await this.browser.currentPage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autokap",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "AI-powered CLI tool for capturing clean screenshots of websites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,18 +18,6 @@
|
|
|
18
18
|
"types": "./dist/cookie-dismiss.d.ts",
|
|
19
19
|
"default": "./dist/cookie-dismiss.js"
|
|
20
20
|
},
|
|
21
|
-
"./dom-serializer": {
|
|
22
|
-
"types": "./dist/dom-serializer.d.ts",
|
|
23
|
-
"default": "./dist/dom-serializer.js"
|
|
24
|
-
},
|
|
25
|
-
"./dom-css-purger": {
|
|
26
|
-
"types": "./dist/dom-css-purger.d.ts",
|
|
27
|
-
"default": "./dist/dom-css-purger.js"
|
|
28
|
-
},
|
|
29
|
-
"./dom-font-inliner": {
|
|
30
|
-
"types": "./dist/dom-font-inliner.d.ts",
|
|
31
|
-
"default": "./dist/dom-font-inliner.js"
|
|
32
|
-
},
|
|
33
21
|
"./logger": {
|
|
34
22
|
"types": "./dist/logger.d.ts",
|
|
35
23
|
"default": "./dist/logger.js"
|
|
@@ -174,10 +162,6 @@
|
|
|
174
162
|
"types": "./dist/server-screenshot-watermark.d.ts",
|
|
175
163
|
"default": "./dist/server-screenshot-watermark.js"
|
|
176
164
|
},
|
|
177
|
-
"./capture-studio-sync": {
|
|
178
|
-
"types": "./dist/capture-studio-sync.d.ts",
|
|
179
|
-
"default": "./dist/capture-studio-sync.js"
|
|
180
|
-
},
|
|
181
165
|
"./cli-contract": {
|
|
182
166
|
"types": "./dist/cli-contract.d.ts",
|
|
183
167
|
"default": "./dist/cli-contract.js"
|
|
@@ -236,7 +220,6 @@
|
|
|
236
220
|
"posthog-node": "^5.26.2",
|
|
237
221
|
"sharp": "^0.34.5",
|
|
238
222
|
"@resvg/resvg-js": "^2.6.2",
|
|
239
|
-
"parse5": "^8.0.0",
|
|
240
223
|
"satori": "^0.26.0",
|
|
241
224
|
"wawoff2": "^2.0.1",
|
|
242
225
|
"ws": "^8.20.0",
|
package/readme.md
CHANGED
|
@@ -16,6 +16,19 @@ cp .env.example .env.local
|
|
|
16
16
|
npm run dev
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## CLI in CI/CD
|
|
20
|
+
|
|
21
|
+
AutoKap can run non-interactively in CI by reading the CLI key from
|
|
22
|
+
`AUTOKAP_API_KEY`; no local `~/.autokap/config.json` is required.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
AUTOKAP_API_KEY=ak_cli_... autokap run <preset-id> --env staging
|
|
26
|
+
AUTOKAP_API_KEY=ak_cli_... autokap auto-recapture --project <project-id> --env local
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Use project environments in the dashboard to map `local`, `staging`, and
|
|
30
|
+
`production` to different base URLs without duplicating presets.
|
|
31
|
+
|
|
19
32
|
## Auth Setup (Supabase)
|
|
20
33
|
|
|
21
34
|
AutoKap uses Supabase Auth for user authentication. You need to configure the following providers in your Supabase dashboard:
|