autokap 1.1.0 → 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 (41) 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 +1 -3
  6. package/dist/billing-operation-logging.js +0 -4
  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/execution-schema.d.ts +143 -331
  19. package/dist/execution-schema.js +43 -28
  20. package/dist/execution-types.d.ts +6 -151
  21. package/dist/execution-types.js +1 -3
  22. package/dist/logger.js +1 -1
  23. package/dist/mockup-html.d.ts +2 -0
  24. package/dist/mockup-html.js +13 -10
  25. package/dist/mockup.js +2 -2
  26. package/dist/opcode-actions.js +0 -2
  27. package/dist/opcode-runner.js +0 -121
  28. package/dist/program-signing.d.ts +50 -72
  29. package/dist/security.js +2 -2
  30. package/dist/server-capture-runtime.d.ts +0 -1
  31. package/dist/server-capture-runtime.js +0 -3
  32. package/dist/server-credit-usage.d.ts +1 -1
  33. package/dist/skill-packaging.d.ts +1 -1
  34. package/dist/skill-packaging.js +1 -11
  35. package/dist/types.d.ts +2 -2
  36. package/dist/web-playwright-local.d.ts +0 -14
  37. package/dist/web-playwright-local.js +0 -194
  38. package/package.json +1 -18
  39. package/readme.md +13 -0
  40. package/assets/skill/STUDIO-SKILL.md +0 -476
  41. package/assets/skill/references/interactive-demo.md +0 -225
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import fs from 'node:fs/promises';
6
6
  const require = createRequire(import.meta.url);
7
7
  const { version } = require('../package.json');
8
8
  import { logger } from './logger.js';
9
- import { writeConfig, deleteConfig, requireConfig, getConfigPath, DEFAULT_API_BASE_URL, getDefaultApiBaseUrl, getDefaultWsUrl, LOCAL_API_BASE_URL, LOCAL_WS_URL, API_BASE_URL_ENV_VAR, WS_URL_ENV_VAR, } from './cli-config.js';
9
+ import { writeConfig, deleteConfig, requireConfig, getConfigPath, DEFAULT_API_BASE_URL, getDefaultApiBaseUrl, getDefaultWsUrl, LOCAL_API_BASE_URL, LOCAL_WS_URL, API_KEY_ENV_VAR, API_BASE_URL_ENV_VAR, WS_URL_ENV_VAR, } from './cli-config.js';
10
10
  import { renderSkillSingleFile, writeSkillExport } from './skill-packaging.js';
11
11
  // ── Program definition ──────────────────────────────────────────────
12
12
  export const program = new Command();
@@ -14,6 +14,12 @@ program
14
14
  .name('autokap')
15
15
  .version(version)
16
16
  .description('AI-powered screenshot capture — local Playwright proxy');
17
+ function getProjectPrimaryUrl(project) {
18
+ return (project.environments.local ??
19
+ project.environments.staging ??
20
+ project.environments.prod ??
21
+ null);
22
+ }
17
23
  function fatal(message) {
18
24
  logger.error(message);
19
25
  process.exit(1);
@@ -205,6 +211,8 @@ program
205
211
  .description('Run a capture using the deterministic opcode engine (local Playwright)')
206
212
  .option('--headed', 'Show browser window for debugging', false)
207
213
  .option('--local', `Use the local AutoKap dev server (${LOCAL_API_BASE_URL})`, false)
214
+ .option('--env <name>', "Project environment to capture against. Falls back to the project's default environment when omitted.")
215
+ .option('--allow-upload-failure', 'Keep a successful capture exit code even if artifact upload fails', false)
208
216
  .option('--output <dir>', 'Optional output directory for local artifact copies')
209
217
  .option('--program <file>', 'Path to a program JSON file')
210
218
  .option('--debug', 'Verbose logging: per-substep timing, opcode dumps, recovery strategy traces', false)
@@ -222,6 +230,59 @@ program
222
230
  const { runLocal } = await import('./cli-runner-local.js');
223
231
  await runLocal(presetId, opts);
224
232
  });
233
+ // ── auto-recapture command ─────────────────────────────────────────
234
+ program
235
+ .command('auto-recapture')
236
+ .description('Run every preset enabled for CI auto-recapture in a project')
237
+ .requiredOption('--project <id>', 'Project ID')
238
+ .option('--env <name>', "Project environment to capture against. Falls back to the project's default environment when omitted.")
239
+ .option('--headed', 'Show browser window for debugging', false)
240
+ .option('--local', `Use the local AutoKap dev server (${LOCAL_API_BASE_URL})`, false)
241
+ .option('--allow-upload-failure', 'Keep a successful capture exit code even if artifact upload fails', false)
242
+ .option('--debug', 'Verbose logging: per-substep timing, opcode dumps, recovery strategy traces', false)
243
+ .action(async (opts) => {
244
+ if (opts.debug) {
245
+ const { setDebugEnabled } = await import('./logger.js');
246
+ setDebugEnabled(true);
247
+ logger.info('[capture] Debug mode enabled — verbose logging on');
248
+ }
249
+ if (opts.local) {
250
+ process.env[API_BASE_URL_ENV_VAR] = LOCAL_API_BASE_URL;
251
+ process.env[WS_URL_ENV_VAR] = LOCAL_WS_URL;
252
+ logger.info(`Using local AutoKap dev server: ${LOCAL_API_BASE_URL}`);
253
+ }
254
+ const config = await requireConfig();
255
+ const data = await requestJson(config, `/api/cli/projects/${opts.project}/auto-recapture-presets`, { headers: authHeaders(config) }, 'Failed to list auto-recapture presets');
256
+ if (data.presets.length === 0) {
257
+ logger.info(`[auto-recapture] No presets enabled for project ${opts.project}`);
258
+ process.exit(0);
259
+ }
260
+ const { runCapture } = await import('./cli-runner.js');
261
+ const failures = [];
262
+ for (const preset of data.presets) {
263
+ const label = preset.name ? `${preset.name} (${preset.id})` : preset.id;
264
+ logger.info(`[auto-recapture] Running ${label}`);
265
+ const result = await runCapture({
266
+ presetId: preset.id,
267
+ env: opts.env,
268
+ headed: opts.headed,
269
+ allowUploadFailure: opts.allowUploadFailure,
270
+ });
271
+ if (!result.success) {
272
+ const error = result.error ?? result.runResult?.error ?? 'capture failed';
273
+ failures.push({ id: preset.id, name: preset.name, error });
274
+ logger.error(`[auto-recapture] Failed ${label}: ${error}`);
275
+ }
276
+ }
277
+ if (failures.length > 0) {
278
+ logger.error(`[auto-recapture] ${failures.length}/${data.presets.length} preset(s) failed: ${failures
279
+ .map((failure) => failure.name ?? failure.id)
280
+ .join(', ')}`);
281
+ process.exit(1);
282
+ }
283
+ logger.success(`[auto-recapture] ${data.presets.length} preset(s) recaptured successfully`);
284
+ process.exit(0);
285
+ });
225
286
  // ── project commands ───────────────────────────────────────────────
226
287
  const projectCmd = program
227
288
  .command('project')
@@ -248,16 +309,23 @@ projectCmd
248
309
  .command('create')
249
310
  .description('Create a project')
250
311
  .requiredOption('--name <name>', 'Project name')
251
- .requiredOption('--url <url>', 'Project URL')
312
+ .requiredOption('--base-url <url>', 'Base URL of the chosen environment')
313
+ .option('--environment <name>', "Environment slot to seed: 'local' or 'prod'", 'local')
252
314
  .option('--description <text>', 'Project description')
253
315
  .action(async (opts) => {
254
316
  const config = await requireConfig();
317
+ const env = opts.environment.toLowerCase();
318
+ if (env !== 'local' && env !== 'prod') {
319
+ logger.error("--environment must be 'local' or 'prod'");
320
+ process.exit(1);
321
+ }
255
322
  const data = await requestJson(config, '/api/v1/projects', {
256
323
  method: 'POST',
257
324
  headers: authHeaders(config, { 'Content-Type': 'application/json' }),
258
325
  body: JSON.stringify({
259
326
  name: opts.name,
260
- url: opts.url,
327
+ environment: env,
328
+ base_url: opts.baseUrl,
261
329
  description: opts.description,
262
330
  }),
263
331
  }, 'Failed to create project');
@@ -492,19 +560,9 @@ presetCmd
492
560
  // Build per-endpoint info with type-specific URL params
493
561
  const endpointEntries = endpoints.map((ep) => {
494
562
  const assetType = ep.asset_type ?? 'screenshot';
495
- const url = assetType === 'interactive_demo'
496
- ? `${cfg.apiBaseUrl}/demo/${presetId}`
497
- : `${cfg.apiBaseUrl}/api/v1/assets/${ep.id}`;
563
+ const url = `${cfg.apiBaseUrl}/api/v1/assets/${ep.id}`;
498
564
  let urlParams;
499
- if (assetType === 'interactive_demo') {
500
- urlParams = {
501
- embed: 'Set to "1" for iframe embedding',
502
- lang: 'Language variant',
503
- theme: 'Color theme ("light" or "dark")',
504
- target: 'Device target ID',
505
- };
506
- }
507
- else if (assetType === 'screenshot') {
565
+ if (assetType === 'screenshot') {
508
566
  urlParams = {
509
567
  lang: 'Language variant',
510
568
  theme: 'Color theme ("light" or "dark")',
@@ -513,8 +571,6 @@ presetCmd
513
571
  quality: 'Image quality 1-100',
514
572
  format: 'Output format: "webp", "png", "jpg"',
515
573
  scale: 'Resolution multiplier (0.5-4)',
516
- render: 'Set to "studio" for Studio render',
517
- slot: 'Studio composition slot',
518
574
  };
519
575
  }
520
576
  else if (assetType === 'clip') {
@@ -523,14 +579,6 @@ presetCmd
523
579
  theme: 'Color theme ("light" or "dark")',
524
580
  target: 'Device target ID',
525
581
  format: 'Output format: "gif" (default), "mp4"',
526
- render: 'Set to "studio" for Studio render',
527
- slot: 'Studio composition slot',
528
- };
529
- }
530
- else if (assetType === 'composition') {
531
- urlParams = {
532
- scale: 'Resolution multiplier (0.5-4)',
533
- format: 'Output format: "png", "webp", "jpg"',
534
582
  };
535
583
  }
536
584
  else {
@@ -555,12 +603,6 @@ presetCmd
555
603
  variants: { langs, themes, targets },
556
604
  endpoints: endpointEntries,
557
605
  };
558
- if (captureMode === 'interactive_demo') {
559
- info.interactive_demo = {
560
- url: `${cfg.apiBaseUrl}/demo/${presetId}`,
561
- embed_url: `${cfg.apiBaseUrl}/demo/${presetId}?embed=1`,
562
- };
563
- }
564
606
  console.log(JSON.stringify(info, null, 2));
565
607
  process.exit(0);
566
608
  });
@@ -617,7 +659,15 @@ authCmd
617
659
  }
618
660
  process.exit(0);
619
661
  }
620
- const startUrl = opts.url || (await loadProject(cfg, projectId)).url;
662
+ let startUrl = opts.url;
663
+ if (!startUrl) {
664
+ const project = await loadProject(cfg, projectId);
665
+ startUrl = getProjectPrimaryUrl(project) ?? undefined;
666
+ }
667
+ if (!startUrl) {
668
+ logger.error(`No environment URL configured for project ${projectId}. Configure local/staging/prod in the AutoKap web UI, or pass --url.`);
669
+ process.exit(1);
670
+ }
621
671
  logger.info(`Opening ${startUrl}`);
622
672
  const { captureAuthSession } = await import('./auth-capture.js');
623
673
  await captureAuthSession({
@@ -840,25 +890,16 @@ const AGENT_PATHS = {
840
890
  windsurf: '.windsurf/rules/autokap-preset.md',
841
891
  copilot: '.github/instructions/autokap-preset.instructions.md',
842
892
  };
843
- const STUDIO_AGENT_PATHS = {
844
- claude: '.claude/commands/autokap-studio.md',
845
- codex: '.agents/skills/autokap-studio/SKILL.md',
846
- cursor: '.cursor/rules/autokap-studio.md',
847
- windsurf: '.windsurf/rules/autokap-studio.md',
848
- copilot: '.github/instructions/autokap-studio.instructions.md',
849
- };
850
893
  program
851
894
  .command('skill')
852
895
  .description('Output or install an AutoKap skill for AI coding agents')
853
896
  .option('--output <path>', 'Write the generated skill output to this path instead of stdout')
854
897
  .option('--agent <name>', 'Target AI coding agent: claude, codex, cursor, windsurf, copilot (auto-resolves output path and packaging mode)')
855
- .option('--type <type>', 'Skill type: preset (default) or studio (composition designer)')
856
898
  .option('--project-url <url>', 'Replace the project URL placeholder in the skill')
857
899
  .option('--project-id <id>', 'Replace the project ID placeholder in the skill')
858
900
  .option('--api-base-url <url>', 'Replace the API base URL placeholder (default: https://autokap.app)')
859
901
  .action(async (opts) => {
860
- const skillType = opts.type === 'studio' ? 'studio' : undefined;
861
- const pathMap = skillType === 'studio' ? STUDIO_AGENT_PATHS : AGENT_PATHS;
902
+ const pathMap = AGENT_PATHS;
862
903
  // Resolve --agent to an output path
863
904
  if (opts.agent) {
864
905
  const agentKey = opts.agent.toLowerCase();
@@ -875,7 +916,7 @@ program
875
916
  try {
876
917
  if (opts.output) {
877
918
  const result = await writeSkillExport({
878
- type: skillType === 'studio' ? 'studio' : 'preset',
919
+ type: 'preset',
879
920
  agent: opts.agent?.toLowerCase(),
880
921
  outputPath: opts.output,
881
922
  placeholders: opts,
@@ -889,7 +930,7 @@ program
889
930
  }
890
931
  else {
891
932
  const content = await renderSkillSingleFile({
892
- type: skillType === 'studio' ? 'studio' : 'preset',
933
+ type: 'preset',
893
934
  agent: opts.agent?.toLowerCase(),
894
935
  placeholders: opts,
895
936
  });
@@ -916,6 +957,10 @@ program
916
957
  // If --cli-key not provided, prompt interactively
917
958
  let cliKey = opts.cliKey;
918
959
  if (!cliKey) {
960
+ if (process.stdin.isTTY === false) {
961
+ logger.error(`CLI key is required in non-interactive shells. Pass --cli-key <key> or set ${API_KEY_ENV_VAR} for CI runs.`);
962
+ process.exit(1);
963
+ }
919
964
  const readline = await import('node:readline');
920
965
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
921
966
  cliKey = await new Promise((resolve) => {