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.
Files changed (42) hide show
  1. package/assets/skill/OPCODE-REFERENCE.md +1 -41
  2. package/assets/skill/README.md +0 -1
  3. package/assets/skill/SKILL.md +9 -32
  4. package/assets/skill/references/examples.md +1 -17
  5. package/dist/billing-operation-logging.d.ts +2 -5
  6. package/dist/billing-operation-logging.js +0 -7
  7. package/dist/capture-strategy.d.ts +2 -8
  8. package/dist/capture-strategy.js +2 -30
  9. package/dist/cli-config.d.ts +2 -1
  10. package/dist/cli-config.js +18 -2
  11. package/dist/cli-contract.d.ts +1 -0
  12. package/dist/cli-contract.js +8 -2
  13. package/dist/cli-runner-local.d.ts +2 -0
  14. package/dist/cli-runner-local.js +12 -21
  15. package/dist/cli-runner.d.ts +4 -0
  16. package/dist/cli-runner.js +30 -50
  17. package/dist/cli.js +89 -44
  18. package/dist/cost-logging.d.ts +1 -1
  19. package/dist/execution-schema.d.ts +143 -331
  20. package/dist/execution-schema.js +43 -28
  21. package/dist/execution-types.d.ts +6 -151
  22. package/dist/execution-types.js +1 -3
  23. package/dist/logger.js +1 -1
  24. package/dist/mockup-html.d.ts +2 -0
  25. package/dist/mockup-html.js +13 -10
  26. package/dist/mockup.js +2 -2
  27. package/dist/opcode-actions.js +0 -2
  28. package/dist/opcode-runner.js +0 -121
  29. package/dist/program-signing.d.ts +50 -72
  30. package/dist/security.js +2 -2
  31. package/dist/server-capture-runtime.d.ts +0 -1
  32. package/dist/server-capture-runtime.js +0 -3
  33. package/dist/server-credit-usage.d.ts +1 -1
  34. package/dist/skill-packaging.d.ts +1 -1
  35. package/dist/skill-packaging.js +1 -11
  36. package/dist/types.d.ts +2 -2
  37. package/dist/web-playwright-local.d.ts +0 -14
  38. package/dist/web-playwright-local.js +0 -194
  39. package/package.json +1 -18
  40. package/readme.md +13 -0
  41. package/assets/skill/STUDIO-SKILL.md +0 -476
  42. 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' | 'video' | 'preset_analysis' | 'ai_chat' | 'interactive_demo_state';
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;
@@ -1,4 +1,4 @@
1
- export type SkillType = 'preset' | 'studio';
1
+ export type SkillType = 'preset';
2
2
  export type SkillAgent = 'claude' | 'codex' | 'cursor' | 'windsurf' | 'copilot';
3
3
  export interface SkillPlaceholderOptions {
4
4
  projectUrl?: string;
@@ -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 type === 'studio' ? STUDIO_SKILL_SOURCE : PRESET_SKILL_SOURCE;
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 composition telemetry (optional, for cost optimization tracking) */
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.0.10",
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: