afterpresets 0.2.0 → 0.4.0

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 (139) hide show
  1. package/README.md +9 -6
  2. package/native-runtime/CMakeLists.txt +82 -0
  3. package/native-runtime/README.md +40 -0
  4. package/native-runtime/THIRD_PARTY_NOTICES.md +14 -0
  5. package/native-runtime/include/ap_native.h +223 -0
  6. package/native-runtime/src/apply.cpp +199 -0
  7. package/native-runtime/src/crypto.cpp +225 -0
  8. package/native-runtime/src/crypto.hpp +51 -0
  9. package/native-runtime/src/dialog.cpp +62 -0
  10. package/native-runtime/src/dialog.hpp +35 -0
  11. package/native-runtime/src/engine.cpp +909 -0
  12. package/native-runtime/src/engine.hpp +232 -0
  13. package/native-runtime/src/fsutil.cpp +291 -0
  14. package/native-runtime/src/fsutil.hpp +57 -0
  15. package/native-runtime/src/json.cpp +326 -0
  16. package/native-runtime/src/json.hpp +70 -0
  17. package/native-runtime/src/platform.hpp +83 -0
  18. package/native-runtime/src/platform_common.cpp +60 -0
  19. package/native-runtime/src/platform_mac.mm +314 -0
  20. package/native-runtime/src/platform_win.cpp +277 -0
  21. package/native-runtime/src/runtime.cpp +473 -0
  22. package/native-runtime/src/util.cpp +169 -0
  23. package/native-runtime/src/util.hpp +32 -0
  24. package/native-runtime/src/zip.cpp +243 -0
  25. package/native-runtime/src/zip.hpp +58 -0
  26. package/native-runtime/third_party/monocypher/LICENCE.md +167 -0
  27. package/native-runtime/third_party/monocypher/monocypher-ed25519.c +500 -0
  28. package/native-runtime/third_party/monocypher/monocypher-ed25519.h +140 -0
  29. package/native-runtime/third_party/monocypher/monocypher.c +2956 -0
  30. package/native-runtime/third_party/monocypher/monocypher.h +321 -0
  31. package/native-runtime/third_party/tinf/LICENSE +22 -0
  32. package/native-runtime/third_party/tinf/crc32.c +57 -0
  33. package/native-runtime/third_party/tinf/tinf.h +140 -0
  34. package/native-runtime/third_party/tinf/tinflate.c +636 -0
  35. package/native-runtime/vendor-files.json +39 -0
  36. package/package.json +7 -4
  37. package/runtime/docs/cep/host-after-effects.md +3 -3
  38. package/runtime/docs/cep/host-premiere.md +4 -4
  39. package/runtime/docs/cep/host.md +10 -2
  40. package/runtime/docs/common/README.md +1 -1
  41. package/runtime/docs/native/README.md +44 -0
  42. package/runtime/docs/native/debugging.md +140 -0
  43. package/runtime/docs/native/rules.md +402 -0
  44. package/runtime/docs/native/testing.md +154 -0
  45. package/runtime/package.json +1 -1
  46. package/runtime/scripts/ae-sdk-docs/config.js +102 -0
  47. package/runtime/scripts/ae-sdk-docs/convert.js +430 -0
  48. package/runtime/scripts/ae-sdk-docs/index.js +314 -0
  49. package/runtime/scripts/ae-sdk-docs/source.js +205 -0
  50. package/runtime/scripts/ae-sdk-docs/split.js +170 -0
  51. package/runtime/scripts/ae-sdk-docs.js +72 -0
  52. package/runtime/src/host.js +1 -1
  53. package/src/agent/cli-group.js +9 -0
  54. package/src/agent/extendscript.js +10 -0
  55. package/src/agent/host-target.js +1 -0
  56. package/src/agent/panels.js +1 -0
  57. package/src/agent/png.js +1 -0
  58. package/src/agent/run-tool.js +3 -0
  59. package/src/{mcp → agent}/snapshot.js +2 -2
  60. package/src/agent/tool-error.js +1 -0
  61. package/src/agent/tools/capture.js +3 -0
  62. package/src/agent/tools/host.js +1 -0
  63. package/src/agent/tools/native.js +1 -0
  64. package/src/agent/tools/panel.js +7 -0
  65. package/src/agent/tools.js +2 -0
  66. package/src/api/error-messages.js +1 -1
  67. package/src/build/build.js +9 -8
  68. package/src/check/check.js +3 -3
  69. package/src/check/native.js +14 -0
  70. package/src/check/pricing.js +1 -1
  71. package/src/cli.js +3 -3
  72. package/src/commands/build.js +8 -2
  73. package/src/commands/check.js +10 -2
  74. package/src/commands/comp.js +6 -0
  75. package/src/commands/dev.js +29 -2
  76. package/src/commands/docs.js +5 -1
  77. package/src/commands/host.js +1 -0
  78. package/src/commands/init.js +12 -7
  79. package/src/commands/panel.js +1 -0
  80. package/src/commands/push.js +9 -2
  81. package/src/commands/releases.js +8 -3
  82. package/src/commands/sdk.js +14 -0
  83. package/src/commands/testers.js +1 -1
  84. package/src/commands/upgrade.js +2 -2
  85. package/src/commands/whoami.js +1 -1
  86. package/src/dev/bridge.js +8 -0
  87. package/src/dev/native.js +3 -0
  88. package/src/dev/session.js +5 -4
  89. package/src/native/build.js +27 -0
  90. package/src/native/cmake/CMakeLists.txt +88 -0
  91. package/src/native/cmake/zig-windows.cmake +19 -0
  92. package/src/native/effect.js +3 -0
  93. package/src/native/install.js +8 -0
  94. package/src/native/installers.js +4 -0
  95. package/src/native/pipl.js +20 -0
  96. package/src/native/restart.js +2 -0
  97. package/src/native/sdk.js +8 -0
  98. package/src/project/docs.js +3 -3
  99. package/src/project/project.js +2 -2
  100. package/src/project/template.js +5 -4
  101. package/src/prompt.js +1 -1
  102. package/src/release/confirm.js +5 -0
  103. package/src/release/native.js +3 -0
  104. package/src/release/publish.js +1 -1
  105. package/src/system/run-command.js +1 -1
  106. package/src/targets.js +1 -1
  107. package/template/cep/AGENTS.md +102 -164
  108. package/template/cep/README.md +7 -3
  109. package/template/cep/docs/code_guide.md +67 -0
  110. package/template/cep/docs/initial_setup.md +63 -42
  111. package/template/cep/docs/release_checklist.md +25 -0
  112. package/template/cep/gitignore +2 -1
  113. package/template/cep/src/features/update-screen/update-screen.js +1 -1
  114. package/template/hosts/AGENTS.two-apps.md +12 -0
  115. package/template/native/AGENTS.md +106 -0
  116. package/template/native/README.md +71 -0
  117. package/template/native/docs/code_guide.md +72 -0
  118. package/template/native/docs/initial_setup.md +154 -0
  119. package/template/native/docs/release_checklist.md +25 -0
  120. package/template/native/effect.json +16 -0
  121. package/template/native/gitignore +9 -0
  122. package/template/native/package.json +14 -0
  123. package/template/native/src/Effect.cpp +224 -0
  124. package/template/native/src/License.cpp +95 -0
  125. package/template/native/src/License.h +29 -0
  126. package/template/native/src/Render.h +68 -0
  127. package/src/commands/mcp.js +0 -7
  128. package/src/mcp/extendscript.js +0 -9
  129. package/src/mcp/panels.js +0 -1
  130. package/src/mcp/protocol.js +0 -4
  131. package/src/mcp/server.js +0 -2
  132. package/src/mcp/tools/account.js +0 -3
  133. package/src/mcp/tools/host.js +0 -1
  134. package/src/mcp/tools/panel.js +0 -7
  135. package/src/mcp/tools/project.js +0 -40
  136. package/src/mcp/tools/releases.js +0 -29
  137. package/template/cep/.mcp.json +0 -8
  138. /package/src/{mcp → agent}/capture.js +0 -0
  139. /package/src/{mcp → agent}/redact.js +0 -0
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // Generates the After Effects SDK topic files for native (C++) projects.
5
+ //
6
+ // node scripts/ae-sdk-docs.js --out <dir> download the pinned guide (cached) and generate
7
+ // node scripts/ae-sdk-docs.js --out <dir> --source <checkout> [--allow-unpinned]
8
+ // options: --cache <dir> (default ~/.afterpresets/cache), --quiet, --json
9
+ //
10
+ // Adobe's guide is not redistributed: it is downloaded by the user's machine
11
+ // from GitHub at the commit pinned in ae-sdk-docs/config.js and checked
12
+ // against the pinned digest. See ../docs/native/README.md.
13
+
14
+ const { generate } = require("./ae-sdk-docs/index");
15
+
16
+ function parseArgs(argv) {
17
+ const opts = {};
18
+ for (let i = 0; i < argv.length; i++) {
19
+ const arg = argv[i];
20
+ const value = () => {
21
+ if (i + 1 >= argv.length) throw new Error(arg + " needs a value.");
22
+ return argv[++i];
23
+ };
24
+ if (arg === "--out") opts.out = value();
25
+ else if (arg === "--source") opts.source = value();
26
+ else if (arg === "--cache") opts.cacheDir = value();
27
+ else if (arg === "--allow-unpinned") opts.allowUnpinned = true;
28
+ else if (arg === "--quiet") opts.quiet = true;
29
+ else if (arg === "--json") opts.json = true;
30
+ else if (arg === "--help" || arg === "-h") opts.help = true;
31
+ else throw new Error("Unknown option " + arg);
32
+ }
33
+ return opts;
34
+ }
35
+
36
+ async function main() {
37
+ let opts;
38
+ try {
39
+ opts = parseArgs(process.argv.slice(2));
40
+ } catch (error) {
41
+ console.error(error.message);
42
+ process.exitCode = 2;
43
+ return;
44
+ }
45
+ if (opts.help || !opts.out) {
46
+ console.log("Usage: node scripts/ae-sdk-docs.js --out <dir> [--source <checkout>] [--allow-unpinned] [--cache <dir>] [--quiet] [--json]");
47
+ if (!opts.help) process.exitCode = 2;
48
+ return;
49
+ }
50
+ const result = await generate(opts);
51
+ if (opts.json) {
52
+ console.log(JSON.stringify(result, null, 2));
53
+ return;
54
+ }
55
+ if (!opts.quiet) {
56
+ const width = Math.max.apply(null, result.files.map((f) => f.name.length));
57
+ result.files.forEach((f) => console.log(f.name.padEnd(width) + " " + String(f.tokens).padStart(6)));
58
+ console.log("");
59
+ }
60
+ const sizes = result.files.map((f) => f.tokens).sort((a, b) => a - b);
61
+ console.log(
62
+ result.files.length + " files from " + result.pages + " pages, about " + result.totalTokens + " tokens (source pages: about " + result.sourceTokens + "). " +
63
+ "Median file " + sizes[Math.floor(sizes.length / 2)] + ", largest " + sizes[sizes.length - 1] + "."
64
+ );
65
+ console.log("Source: commit " + result.commit + ", " + result.digest + " (" + result.from + ")");
66
+ result.warnings.forEach((w) => console.warn("warning: " + w));
67
+ }
68
+
69
+ main().catch((error) => {
70
+ console.error("ae-sdk-docs: " + error.message);
71
+ process.exitCode = 1;
72
+ });
@@ -1 +1 @@
1
- (function(p){"use strict";var c=p.AP,i=c._,S=/^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$/,y="EvalScript error.",o="idle",s=null,f=[];function a(n){var e=JSON.stringify(n===void 0?null:n);return e===void 0&&(e="null"),e.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}i.jsxLiteral=a;function d(n,e){for(var t=[],r=0;r<e.length;r++)t.push(a(e[r]));return["(function () {"," function apQ(s) { s = String(s); return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')"," .replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\n').replace(/\\t/g, '\\\\t') + '\"'; }"," try {"," var r = "+n+"("+t.join(", ")+");"," if (r === undefined || r === null) return 'null';"," return String(r);"," } catch (e) {"," return '{\"error\":' + apQ(e && e.message ? e.message : e) + '}';"," }","}())"].join("\n")}i.wrapHostCall=d;function h(n,e){var t=i.cs();if(!t){e(JSON.stringify({error:"CEP host API is unavailable."}));return}t.evalScript(n,e)}function v(){try{var n=i.cs(),e=n&&n.getHostEnvironment();return e&&e.appName?String(e.appName):null}catch(t){return null}}i.hostAppName=v;function R(n){return!!n&&typeof n.code=="string"&&!!n.code}function _(){var n=p.AP_JSX;if(!n||typeof n!="object")return{missing:"This bundle has no host script (AP_JSX). Rebuild it with the AfterPresets CLI."};var e=v();return e&&Object.prototype.hasOwnProperty.call(n,e)&&R(n[e])?n[e]:{missing:"This extension has no host script for "+(e||"this app")+"."}}function O(){var n=_();return n.missing?"'AP_LOAD_ERROR:' + "+a(n.missing):"try { eval("+a(n.code)+"); 'ok'; } catch (e) { 'AP_LOAD_ERROR:' + (e && e.message ? e.message : e); }"}function g(n){if(n=n||function(){},o==="loaded"){n(null);return}if(o==="failed"){n(s);return}if(f.push(n),o==="loading")return;o="loading";function e(r){o=r?"failed":"loaded",s=r,r&&i.log("error",r);var u=f;f=[];for(var l=0;l<u.length;l++)u[l](r)}var t=O();h(t,function(r){e(r==="ok"?null:String(r||"Could not load host script.").replace(/^AP_LOAD_ERROR:/,"Could not load host script: "))})}i.preloadHost=function(){g(null)};function A(n){if(n===y)return{error:"The host script failed to run."};if(n==null||n===""||n==="undefined")return null;try{return JSON.parse(n)}catch(e){return{error:"The host returned a non-JSON result.",raw:String(n)}}}i.parseHostResult=A,c.host={eval:function(n,e,t){if(typeof e=="function"&&t===void 0&&(t=e,e=[]),t=typeof t=="function"?t:function(){},typeof n!="string"||!S.test(n)){t({error:"Invalid host function name: "+String(n)});return}e==null&&(e=[]),Object.prototype.toString.call(e)!=="[object Array]"&&(e=[e]);var r=d(n,e);g(function(u){if(u){t({error:String(u)});return}h(r,function(l){t(A(l))})})},reload:function(){o="idle",s=null}}})(typeof window!="undefined"?window:this);
1
+ (function(d){"use strict";var s=d.AP,i=s._,S=/^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$/,y="EvalScript error.",o="idle",f=null,p=[];function a(e){var t=JSON.stringify(e===void 0?null:e);return t===void 0&&(t="null"),t.replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}i.jsxLiteral=a;function h(e,t){for(var n=[],r=0;r<t.length;r++)n.push(a(t[r]));return["(function () {"," function apQ(s) { s = String(s); return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')"," .replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\n').replace(/\\t/g, '\\\\t') + '\"'; }"," try {"," var r = "+e+"("+n.join(", ")+");"," if (r === undefined || r === null) return 'null';"," return String(r);"," } catch (e) {"," return '{\"error\":' + apQ(e && e.message ? e.message : e) + '}';"," }","}())"].join("\n")}i.wrapHostCall=h;function v(e,t){var n=i.cs();if(!n){t(JSON.stringify({error:"CEP host API is unavailable."}));return}n.evalScript(e,t)}function c(){try{var e=i.cs(),t=e&&e.getHostEnvironment();return t&&t.appName?String(t.appName):null}catch(n){return null}}i.hostAppName=c;function R(e){return!!e&&typeof e.code=="string"&&!!e.code}function _(){var e=d.AP_JSX;if(!e||typeof e!="object")return{missing:"This bundle has no host script (AP_JSX). Rebuild it with the AfterPresets CLI."};var t=c();return t&&Object.prototype.hasOwnProperty.call(e,t)&&R(e[t])?e[t]:{missing:"This extension has no host script for "+(t||"this app")+"."}}function O(){var e=_();return e.missing?"'AP_LOAD_ERROR:' + "+a(e.missing):"try { eval("+a(e.code)+"); 'ok'; } catch (e) { 'AP_LOAD_ERROR:' + (e && e.message ? e.message : e); }"}function g(e){if(e=e||function(){},o==="loaded"){e(null);return}if(o==="failed"){e(f);return}if(p.push(e),o==="loading")return;o="loading";function t(r){o=r?"failed":"loaded",f=r,r&&i.log("error",r);var u=p;p=[];for(var l=0;l<u.length;l++)u[l](r)}var n=O();v(n,function(r){t(r==="ok"?null:String(r||"Could not load host script.").replace(/^AP_LOAD_ERROR:/,"Could not load host script: "))})}i.preloadHost=function(){g(null)};function A(e){if(e===y)return{error:"The host script failed to run."};if(e==null||e===""||e==="undefined")return null;try{return JSON.parse(e)}catch(t){return{error:"The host returned a non-JSON result.",raw:String(e)}}}i.parseHostResult=A,s.host={eval:function(e,t,n){if(typeof t=="function"&&n===void 0&&(n=t,t=[]),n=typeof n=="function"?n:function(){},typeof e!="string"||!S.test(e)){n({error:"Invalid host function name: "+String(e)});return}t==null&&(t=[]),Object.prototype.toString.call(t)!=="[object Array]"&&(t=[t]);var r=h(e,t);g(function(u){if(u){n({error:String(u)});return}v(r,function(l){n(A(l))})})},reload:function(){o="idle",f=null}},Object.defineProperty(s.host,"app",{enumerable:!0,get:c})})(typeof window!="undefined"?window:this);
@@ -0,0 +1,9 @@
1
+ "use strict";const c=require("fs"),f=require("path"),{parseArgs:l}=require("../args"),{UsageError:o}=require("../errors"),{runTool:h}=require("./run-tool"),p={out:{type:"string",alias:"o"}};function u(n,t){if(n===void 0)return;const e=Number(n);if(!Number.isFinite(e))throw new o(t+" must be a number; got "+JSON.stringify(n)+".");return e}function w(n,t){if(n!==void 0)return String(n).split(",").map(e=>e.trim()).filter(Boolean).map(e=>u(e,t))}async function g(n,t,e,s){if([n.code!==void 0,n.file!==void 0,t.length>0].filter(Boolean).length>1)throw new o("Pass the "+s+" one way: as an argument, with -e, or with --file.");if(n.file!==void 0){const r=f.resolve(e.cwd,n.file);if(!c.existsSync(r))throw new o("File not found: "+r);return c.readFileSync(r,"utf8")}if(n.code!==void 0)return String(n.code);if(t.length===1&&t[0]==="-")return y(e);if(t.length)return t.join(" ");throw new o("Pass the "+s+": as an argument, -e '<code>', --file <path>, or - to read stdin.")}function y(n){const t=n.stdin||process.stdin;return new Promise((e,s)=>{let a="";t.setEncoding&&t.setEncoding("utf8"),t.on("data",r=>a+=r),t.on("end",()=>e(a)),t.on("error",s)})}function b(n,t){n.log("Usage: ap "+t.name+` <command> [options]
2
+ `),n.log(t.description+`
3
+ `),t.subcommands.forEach(e=>n.log(" "+n.style.cyan(e.name.padEnd(13))+e.summary)),n.log(`
4
+ `+n.style.dim("`ap "+t.name+" <command> --help` for details."))}function U(n,t,e){n.log("Usage: "+e.usage+`
5
+ `),n.log(e.summary+(e.details?`
6
+
7
+ `+e.details:""))}function j(n){const t="ap "+n.name+" <"+n.subcommands.map(e=>e.name).join("|")+"> [options]";return{name:n.name,summary:n.summary,usage:t,description:n.description+`
8
+
9
+ Commands: `+n.subcommands.map(e=>e.name).join(", ")+". Run `ap "+n.name+" <command> --help`.",raw:!0,subcommands:n.subcommands,async run(e,s){const a=s[0];if(!a||a==="help"||a==="--help"||a==="-h")return b(e.out,n),a?0:2;const r=n.subcommands.find(i=>i.name===a||(i.aliases||[]).indexOf(a)!==-1);if(!r)throw new o("Unknown command: ap "+n.name+" "+a,"Commands: "+n.subcommands.map(i=>i.name).join(", ")+".");let m;try{m=l(s.slice(1),Object.assign({},r.image?p:{},r.flags||{}))}catch(i){throw i instanceof o&&(i.hint=i.hint||"Usage: "+r.usage),i}if(m.flags.help)return U(e.out,n,r),0;let d;try{d=await r.input(m.flags,m.positionals,e)}catch(i){throw i instanceof o&&(i.hint=i.hint||"Usage: "+r.usage),i}return Object.keys(d).forEach(i=>d[i]===void 0&&delete d[i]),h(e,r.tool,d,{out:m.flags.out,label:r.label,exitFor:r.exitFor,deps:e.toolDeps})}}}module.exports={createGroupCommand:j,number:u,numberList:w,codeFrom:g};
@@ -0,0 +1,10 @@
1
+ "use strict";function n(e){return JSON.stringify(e===void 0?null:e).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function o(e){try{return new Function("return ("+e+`
2
+ );`),!0}catch{return!1}}const m=["function apStr(s) { if (s instanceof Array) { var a = []; for (var i = 0; i < s.length; i++) a.push(apStr(s[i])); return '[' + a.join(',') + ']'; } return (s === null || s === undefined) ? String(s) : String(s); }",`function apQ(s) { s = apStr(s); return '"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/"/g, '\\\\"')`,` .replace(/\\r/g, '\\\\r').replace(/\\n/g, '\\\\n').replace(/\\t/g, '\\\\t') + '"'; }`,"function apSer(v, depth) {"," if (v === null || v === undefined) return 'null';"," var t = typeof v;"," if (t === 'number') return isFinite(v) ? String(v) : 'null';"," if (t === 'boolean') return v ? 'true' : 'false';"," if (t === 'string') return apQ(v);"," if (t === 'function') return 'null';"," if (depth > 6) return apQ('[nested too deep]');"," var parts = [], i, k, n = 0;"," if (v instanceof Array) {"," for (i = 0; i < v.length && i < 10000; i++) parts.push(apSer(v[i], depth + 1));"," return '[' + parts.join(',') + ']';"," }"," if (v instanceof Date) return apQ(v.toUTCString());"," try {"," for (k in v) {"," if (n++ >= 500) break;"," var item; try { item = v[k]; } catch (e1) { continue; }"," if (typeof item === 'function') continue;"," parts.push(apQ(k) + ':' + apSer(item, depth + 1));"," }"," } catch (e2) { parts = []; }"," if (!parts.length && t === 'object' && !(v.constructor === Object)) { try { return apQ(v.toString()); } catch (e3) { return 'null'; } }"," return '{' + parts.join(',') + '}';","}","function apJson(v) {"," var j = null;"," try { if (typeof JSON !== 'undefined' && JSON.stringify) j = JSON.stringify(v); } catch (e) { j = null; }"," return (j === null || j === undefined) ? apSer(v, 0) : j;","}"];function t(e,r){const u=!(r&&r.undo===!1),f=o(e)?"return ("+e+`
3
+ );`:e,i=["(function () {"].concat(m,[" var apUndo = "+(u?"true":"false")+";"," if (apUndo) app.beginUndoGroup("+n("AfterPresets agent")+");"," try {"," var apResult = (function () {"]),d=[" }());",` return '{"ok":true,"value":' + (apResult === undefined ? 'null' : apJson(apResult)) + '}';`," } catch (e) {",` return '{"ok":false,"error":' + apQ(e && e.message ? e.message : e) + ',"line":' + (e && e.line ? Number(e.line) : 'null') + '}';`," } finally {"," if (apUndo) app.endUndoGroup();"," }","}())"];return{script:i.concat([f],d).join(`
4
+ `),lineOffset:i.length}}function p(){return t(["var p = app.project;","return { name: p.file ? p.file.name : null, path: p.file ? p.file.fsName : null,"," unsaved: p.dirty === true, items: p.numItems, aeVersion: app.version };"].join(`
5
+ `),{undo:!1}).script}function v(e){return typeof e=="string"&&/(^|[\\/])AfterPresets scratch \d+\.aep$/.test(e)}function s(e){return t(["var p = app.project;",e==="save"?"if (p.file) p.save();":"","p.close(CloseOptions.DO_NOT_SAVE_CHANGES);","app.newProject();","var f = new File(Folder.temp.fsName + '/AfterPresets scratch ' + new Date().getTime() + '.aep');","app.project.save(f);","return { name: app.project.file ? app.project.file.name : null, path: app.project.file ? app.project.file.fsName : null, items: app.project.numItems };"].join(`
6
+ `),{undo:!1}).script}function h(e){return t(["var p = app.project;","var want = "+n(e.comp===void 0?null:e.comp)+";","var at = "+n(e.at||[])+";","var dir = "+n(e.dir)+";","function comps() { var out = []; for (var i = 1; i <= p.numItems; i++) if (p.item(i) instanceof CompItem) out.push(p.item(i)); return out; }","function listed(list) { var names = []; for (var i = 0; i < list.length && i < 25; i++) names.push(apQ(list[i].name) + ' (id ' + list[i].id + ')'); return names.join(', ') + (list.length > 25 ? ', ...' : ''); }","var all = comps();","var c = null;","if (want === null) {"," if (p.activeItem instanceof CompItem) c = p.activeItem;"," else if (all.length === 1) c = all[0];"," else if (!all.length) throw new Error('The project has no composition.');"," else throw new Error('No composition is active. Pass comp (name or id): ' + listed(all));","} else if (typeof want === 'number') {"," try { c = p.itemByID(want); } catch (e) { c = null; }"," if (!(c instanceof CompItem)) throw new Error('No composition with id ' + want + '. Compositions: ' + (all.length ? listed(all) : 'none'));","} else {"," var found = [];"," for (var i = 0; i < all.length; i++) if (all[i].name === want) found.push(all[i]);"," if (found.length > 1) throw new Error(found.length + ' compositions are named ' + apQ(want) + '; pass the id: ' + listed(found));"," if (!found.length) throw new Error('No composition named ' + apQ(want) + '. Compositions: ' + (all.length ? listed(all) : 'none'));"," c = found[0];","}","if (typeof c.saveFrameToPng !== 'function') throw new Error('This version of After Effects (' + app.version + ') cannot render frames from scripts.');","var fd = c.frameDuration;","var times = [];","if (!at.length) times.push(c.time);","for (var k = 0; k < at.length; k++) times.push(at[k].frame !== undefined && at[k].frame !== null ? at[k].frame * fd : at[k].seconds);","for (var v = 0; v < times.length; v++) {"," var t = times[v];"," if (!(t >= 0) || t > c.duration - fd / 2) throw new Error('Time ' + t + ' s is outside the composition: 0 to ' + (Math.round(c.duration / fd) - 1) * fd + ' s (frames 0 to ' + (Math.round(c.duration / fd) - 1) + ').');","}","var purged = false;","if ("+(e.purge===!1?"false":"true")+") { app.purge(PurgeTarget.IMAGE_CACHES); purged = true; }","var origBpc = p.bitsPerChannel;","var switched = false;","if (origBpc === 32 && "+(e.keep32?"false":"true")+") { p.bitsPerChannel = 16; switched = true; }","var frames = [];","try {","for (var n = 0; n < times.length; n++) {"," var t = times[n];"," var f = new File(dir + '/frame-' + n + '.png');"," var started = new Date().getTime();"," var pending = c.saveFrameToPng(t, f);"," var waited = false;"," if (pending && typeof pending.wait === 'function') {"," try { pending.wait(); } catch (e) {}"," waited = true;"," if (pending._hasException) throw new Error('After Effects could not render ' + t + ' s: ' + pending._exception);"," }"," frames.push({ seconds: t, frame: Math.round(t / fd), file: f.fsName, waited: waited, renderMs: waited ? new Date().getTime() - started : null });","}","} finally { if (switched) p.bitsPerChannel = origBpc; }","return { comp: c.name, id: c.id, width: c.width, height: c.height, pixelAspect: c.pixelAspect, frameRate: c.frameRate,"," duration: c.duration, frames: frames, bitsPerChannel: origBpc, renderedBpc: switched ? 16 : origBpc, purged: purged };"].join(`
7
+ `),{undo:!1}).script}function g(e,r){return t(["var paths = "+n(e)+";","var g = $.global;","if (!g.__apDialogs) g.__apDialogs = { fo: File.openDialog, fp: File.prototype.openDlg, so: Folder.selectDialog, sp: Folder.prototype.selectDlg };","var real = g.__apDialogs;","function restore() { File.openDialog = real.fo; File.prototype.openDlg = real.fp; Folder.selectDialog = real.so; Folder.prototype.selectDlg = real.sp; }","function files(multi) { restore(); var out = []; for (var i = 0; i < paths.length; i++) out.push(new File(paths[i])); return multi ? out : out[0]; }","function folderPick() { restore(); return new Folder(paths[0]); }",r?"Folder.selectDialog = folderPick; Folder.prototype.selectDlg = folderPick;":"File.openDialog = function (a, b, multi) { return files(multi === true); }; File.prototype.openDlg = function (a, b, multi) { return files(multi === true); };","return { installed: "+(r?"Folder.selectDialog === folderPick":"File.openDialog !== real.fo")+" };"].join(`
8
+ `),{undo:!1}).script}function l(){return t(["var p = app.project;","if (!p) return { name: null, path: null, items: 0, sequences: 0, sequenceNames: [], activeSequence: null, version: app.version };","var names = [];","var count = p.sequences ? p.sequences.numSequences : 0;","for (var i = 0; i < count && i < 50; i++) names.push(p.sequences[i].name);","return { name: p.name, path: p.path || null, items: p.rootItem ? p.rootItem.children.numItems : 0, sequences: count,"," sequenceNames: names, activeSequence: p.activeSequence ? p.activeSequence.name : null, version: app.version };"].join(`
9
+ `),{undo:!1}).script}function c(e){return t(["var before = app.project ? app.project.path : null;",e==="save"?"if (app.project) app.project.save();":"","var stamp = new Date().getTime();","var file = new File(Folder.temp.fsName + '/AfterPresets scratch ' + stamp + '.prproj');","var created = app.newProject(file.fsName);","if (!created) throw new Error('Premiere Pro did not create the scratch project.');","var opened = false;","for (var i = 0; i < app.projects.numProjects; i++) if (app.projects[i].path === before) opened = true;","return { name: app.project.name, path: app.project.path, previous: before, previousStillOpen: opened };"].join(`
10
+ `),{undo:!1}).script}const a={AEFT:{appName:"After Effects",undo:!0,projectInfoScript:p,scratchProjectScript:s,scratchClosesProject:!0,evalExample:"app.project.activeItem.numLayers"},PPRO:{appName:"Premiere Pro",undo:!1,projectInfoScript:l,scratchProjectScript:c,scratchClosesProject:!1,evalExample:"app.project.activeSequence.name"}};function j(e){return a[e]||a.AEFT}module.exports={literal:n,isExpression:o,wrapEval:t,projectInfoScript:p,scratchProjectScript:s,isAeScratchPath:v,pproProjectInfoScript:l,pproScratchProjectScript:c,chooseFileScript:g,captureFramesScript:h,HOST_ADAPTERS:a,hostAdapter:j};
@@ -0,0 +1 @@
1
+ "use strict";const{ToolError:i}=require("./tool-error"),{findProjectRoot:w}=require("../project/project"),{BRIDGE_PORTS:P,BRIDGE_TITLE:m,bridgeStatus:T}=require("../dev/bridge"),{targetFor:x}=require("../targets"),c=["AEFT","PPRO"];function l(t){const e=x("cep",t);return e?e.appName:t}function R(t){const e=t.map(l);return e.length>1?e.slice(0,-1).join(", ")+" or "+e[e.length-1]:e[0]}function d(t){return w(t.ctx.cwd)?t.project():null}function h(t){return!!(t&&t.settings.platform!=="native"&&t.panels&&t.panels.length)}function f(t){if(!t)return c;const e=(t.settings.hosts||[]).map(s=>s.app).filter(s=>c.indexOf(s)!==-1);return e.length?e:c}function u(t,e){const s=R(e);let r;try{r=T(t.ctx)}catch{r=null}const n="No connection to "+s+". Without a panel, host tools go through the AfterPresets dev bridge (a hidden development extension). ";return r?r.foreign?new i(n+r.dir+" exists but was not created by AfterPresets; ask the user to move it, then run `ap host bridge install`."):r.installed?r.current?new i(n+"It is installed, but "+s+" is not running or has not loaded it: the app loads it at launch. If the app is open, ask the user to save their work and restart it once. Run `ap host bridge` for details."):new i(n+"The installed copy is out of date. Run `ap host bridge install`, then ask the user to restart "+s+" once."):new i(n+"It is not installed. Run `ap host bridge install`, then ask the user to restart "+s+" once (save their work first)."):new i(n+"This computer has no CEP extensions folder (macOS and Windows only).")}function g(t){return t.bridgePorts||P}function A(t){async function e(r){for(const n of r){const o=g(t)[n],a=t.panels.connections&&t.panels.connections.get(o);if(!(a&&a.browser.isConnected()&&!a.page.isClosed())){const p=await t.panels.pageTitles(o);if(!p||p.indexOf(m)===-1)continue}const b=await t.panels.connectPort(o,"the AfterPresets dev bridge in "+l(n),()=>u(t,[n]));return{via:"bridge",app:n,page:b.page,port:o}}throw u(t,r)}async function s(r){const n=d(t);if(h(n)){const{page:o}=await t.panels.connect(n,r);return{via:"panel",page:o,project:n}}if(r)throw new i("This project has no panels; leave out `panel` (host tools use the AfterPresets dev bridge).");return e(f(n))}return{resolve:s,bridge:e}}module.exports={createHostTarget:A,bridgeUnreachable:u,bridgeApps:f,bridgePorts:g,usesPanels:h,projectOrNull:d,appNameOf:l};
@@ -0,0 +1 @@
1
+ "use strict";const{hostAppNames:w}=require("../targets"),{projectDebugPort:O}=require("../config"),{ToolError:d}=require("./tool-error"),m=500;function y(s){const r=O(s.settings);return s.panels.map((i,o)=>({id:i.id,type:i.type,title:i.title,port:r+o}))}function b(s,r){const i=y(s);if(!r)return i[0];const o=i.find(c=>c.id===r);if(!o)throw new d("No panel "+JSON.stringify(r)+". Panels: "+i.map(c=>c.id).join(", ")+".");return o}function C(s,r){return new d('Panel "'+s.id+'" is not reachable on port '+s.port+". Make sure the dev build is linked (`ap dev --background`, or `ap dev` in a terminal) and the panel is open in "+w(r.settings)+" (Window > Extensions > "+(s.title||r.settings.name)+(s.type==="modal"?"; modal panels open from code with AP.panels.open":"")+"). Restart "+w(r.settings)+" after adding a panel or after the first `ap dev`.")}function q(s){const r=s||{},i=r.fetch||((t,e)=>fetch(t,e)),o=new Map;function c(){return r.chromium||require("playwright-core").chromium}async function h(t){try{return(await i("http://127.0.0.1:"+t+"/json/version",{signal:AbortSignal.timeout(1500)})).ok}catch{return!1}}function f(t,e){e.push(Object.assign({at:new Date().toISOString()},t)),e.length>m&&e.splice(0,e.length-m)}function v(t,e){t.on("console",n=>f({level:n.type(),text:n.text()},e)),t.on("pageerror",n=>f({level:"error",text:"Uncaught "+(n&&n.stack?n.stack:String(n))},e)),t.on("load",()=>f({level:"info",text:"[page loaded] "+t.url()},e))}function P(t){const e=[];return t.contexts().forEach(n=>e.push.apply(e,n.pages())),e.find(n=>!/^devtools:/.test(n.url()))||e[0]||null}async function g(t,e,n){const a=o.get(t);if(a&&a.browser.isConnected()&&!a.page.isClosed())return a;if(a&&o.delete(t),!await h(t))throw n();let l;try{l=await c().connectOverCDP("http://127.0.0.1:"+t,{timeout:1e4,noDefaults:!0})}catch(S){throw new d("Could not attach to "+e+" on port "+t+": "+S.message)}const p=P(l);if(!p)throw await l.close().catch(()=>{}),n();const u={browser:l,page:p,logs:[]};return v(p,u.logs),l.on("disconnected",()=>{o.get(t)===u&&o.delete(t)}),o.set(t,u),u}async function A(t,e){const n=b(t,e),a=await g(n.port,'panel "'+n.id+'"',()=>C(n,t));return Object.assign({panel:n},a)}async function k(t){try{const e=await i("http://127.0.0.1:"+t+"/json/list",{signal:AbortSignal.timeout(1500)});if(!e.ok)return null;const n=await e.json();return Array.isArray(n)?n.map(a=>String(a&&a.title||"")):null}catch{return null}}async function x(){const t=Array.from(o.values());o.clear(),await Promise.all(t.map(e=>e.browser.close().catch(()=>{})))}return{connect:A,connectPort:g,reachable:h,pageTitles:k,closeAll:x,connections:o}}module.exports={createPanelConnections:q,panelPorts:y,resolvePanel:b};
@@ -0,0 +1 @@
1
+ "use strict";const b=require("zlib"),I=Buffer.from([137,80,78,71,13,10,26,10]),k={0:1,2:3,4:2,6:4};function T(t){return!t||t.length<57||!t.subarray(0,8).equals(I)?!1:t.subarray(t.length-8,t.length-4).toString("latin1")==="IEND"}function D(t){if(!t||t.length<33||!t.subarray(0,8).equals(I)||t.toString("latin1",12,16)!=="IHDR")throw new Error("Not a PNG file.");return{width:t.readUInt32BE(16),height:t.readUInt32BE(20),bitDepth:t[24],colorType:t[25],interlace:t[28]}}function G(t,n,e){const o=t+n-e,r=Math.abs(o-t),l=Math.abs(o-n),s=Math.abs(o-e);return r<=l&&r<=s?t:l<=s?n:e}function N(t){const n=D(t),e=k[n.colorType];if(!e||n.bitDepth!==8&&n.bitDepth!==16||n.interlace!==0)throw new Error("Unsupported PNG layout (color type "+n.colorType+", "+n.bitDepth+" bit, interlace "+n.interlace+").");const o=[];let r=8;for(;r+8<=t.length;){const h=t.readUInt32BE(r),i=t.toString("latin1",r+4,r+8);if(i==="IDAT"&&o.push(t.subarray(r+8,r+8+h)),i==="IEND")break;r+=12+h}const l=b.inflateSync(Buffer.concat(o)),s=e*(n.bitDepth/8),d=n.width*s;if(l.length<(d+1)*n.height)throw new Error("PNG data is truncated.");const w=Buffer.alloc(d*n.height);for(let h=0;h<n.height;h++){const i=l[h*(d+1)],a=h*(d+1)+1,u=h*d;for(let c=0;c<d;c++){const g=c>=s?w[u+c-s]:0,f=h>0?w[u-d+c]:0,y=h>0&&c>=s?w[u-d+c-s]:0,E=l[a+c];let B;if(i===0)B=E;else if(i===1)B=E+g;else if(i===2)B=E+f;else if(i===3)B=E+(g+f>>1);else if(i===4)B=E+G(g,f,y);else throw new Error("Bad PNG filter "+i+".");w[u+c]=B&255}}const x=new Uint8Array(n.width*n.height*4),p=n.bitDepth/8;for(let h=0,i=0;h<n.width*n.height;h++,i+=s){const a=y=>w[i+y*p];let u,c,g,f=255;e===1||e===2?(u=c=g=a(0),e===2&&(f=a(1))):(u=a(0),c=a(1),g=a(2),e===4&&(f=a(3))),x.set([u,c,g,f],h*4)}return{width:n.width,height:n.height,rgba:x}}const S=(()=>{const t=new Int32Array(256);for(let n=0;n<256;n++){let e=n;for(let o=0;o<8;o++)e=e&1?3988292384^e>>>1:e>>>1;t[n]=e}return t})();function C(t){let n=-1;for(let e=0;e<t.length;e++)n=S[(n^t[e])&255]^n>>>8;return(n^-1)>>>0}function M(t,n){const e=Buffer.alloc(4);e.writeUInt32BE(n.length);const o=Buffer.concat([Buffer.from(t,"latin1"),n]),r=Buffer.alloc(4);return r.writeUInt32BE(C(o)),Buffer.concat([e,o,r])}function U(t){const n=Buffer.alloc(13);n.writeUInt32BE(t.width,0),n.writeUInt32BE(t.height,4),n[8]=8,n[9]=6;const e=t.width*4,o=Buffer.alloc((e+1)*t.height);for(let r=0;r<t.height;r++)o[r*(e+1)]=0,Buffer.from(t.rgba.buffer,t.rgba.byteOffset+r*e,e).copy(o,r*(e+1)+1);return Buffer.concat([I,M("IHDR",n),M("IDAT",b.deflateSync(o)),M("IEND",Buffer.alloc(0))])}function P(t,n){if(n<=1)return t;const e=Math.max(1,Math.floor(t.width/n)),o=Math.max(1,Math.floor(t.height/n)),r=new Uint8Array(e*o*4);for(let l=0;l<o;l++)for(let s=0;s<e;s++){let d=0,w=0,x=0,p=0,h=0;for(let a=0;a<n;a++){const u=l*n+a;if(u>=t.height)break;for(let c=0;c<n;c++){const g=s*n+c;if(g>=t.width)break;const f=(u*t.width+g)*4,y=t.rgba[f+3];d+=t.rgba[f]*y,w+=t.rgba[f+1]*y,x+=t.rgba[f+2]*y,p+=y,h++}}const i=(l*e+s)*4;p>0&&(r[i]=Math.round(d/p),r[i+1]=Math.round(w/p),r[i+2]=Math.round(x/p)),r[i+3]=Math.round(p/h)}return{width:e,height:o,rgba:r}}function A(t,n,e){const o=Math.max(t,n);return e>0&&o>e?Math.ceil(o/e):1}function R(t,n){const e=D(t),o=A(e.width,e.height,n);if(o===1)return{png:t,width:e.width,height:e.height,factor:1};let r;try{r=N(t)}catch{return{png:t,width:e.width,height:e.height,factor:1}}const l=P(r,o);return{png:U(l),width:l.width,height:l.height,factor:o}}module.exports={isCompletePng:T,pngInfo:D,decodePng:N,encodePng:U,shrink:P,shrinkFactor:A,fitPng:R};
@@ -0,0 +1,3 @@
1
+ "use strict";const u=require("fs"),y=require("os"),s=require("path"),{createAgentTools:S}=require("./tools"),{findProjectRoot:w}=require("../project/project"),E=40;function h(t){const n=w(t.cwd);return n?s.join(n,"dist-dev","shots"):s.join(y.tmpdir(),"afterpresets-shots")}function j(t){try{u.readdirSync(t).filter(r=>/\.png$/.test(r)).map(r=>({f:r,t:u.statSync(s.join(t,r)).mtimeMs})).sort((r,i)=>i.t-r.t).slice(E).forEach(r=>u.rmSync(s.join(t,r.f),{force:!0}))}catch{}}function v(t){return new Date(t.now()).toISOString().replace(/[-:]/g,"").replace(/\..*$/,"").replace("T","-")}function q(t,n,r,i){if(n.out){const o=s.resolve(t.cwd,n.out);if(i===1)return o;const a=s.extname(o)||".png";return o.slice(0,o.length-s.extname(o).length)+"-"+(r+1)+a}return s.join(h(t),(n.label||"image")+"-"+v(t)+(i>1?"-"+(r+1):"")+".png")}function b(t,n,r){return n.map((i,o)=>{const a=q(t,r,o,n.length);return u.mkdirSync(s.dirname(a),{recursive:!0}),u.writeFileSync(a,Buffer.from(i.data,"base64")),a})}async function k(t,n,r,i){const o=i||{},a=S(t,Object.assign({onUnexpectedError:e=>{t.env&&t.env.AP_DEBUG&&t.stderr.write(String(e&&e.stack?e.stack:e)+`
2
+ `)}},o.deps||{}));let c;try{c=await a.call(n,r)}finally{await a.close()}const g=c&&c.content||[],l=g.filter(e=>e.type==="text").map(e=>e.text).join(`
3
+ `),m=g.filter(e=>e.type==="image"&&e.data);let p=[];if(m.length&&!c.isError){const e=o.out?null:h(t);p=b(t,m,o),e&&j(e)}const d=!c.isError&&o.exitFor&&o.exitFor(l)||0;return c.isError?(t.out.error(l||"Failed."),1):(l&&t.out.log(l),d||(p.forEach(e=>{const f=s.relative(t.cwd,e);t.out.log("Image: "+(f&&!f.startsWith("..")&&!s.isAbsolute(f)?f:e))}),0))}module.exports={runTool:k};
@@ -1,2 +1,2 @@
1
- "use strict";function N(){for(var o={A:1,BUTTON:1,INPUT:1,SELECT:1,TEXTAREA:1,SUMMARY:1},c={SCRIPT:1,STYLE:1,TEMPLATE:1,NOSCRIPT:1,HEAD:1,META:1,LINK:1},x={A:"link",BUTTON:"button",SELECT:"combobox",TEXTAREA:"textbox",IMG:"img",UL:"list",OL:"list",LI:"listitem",DIALOG:"dialog",LABEL:"label",SUMMARY:"button"},p={checkbox:"checkbox",radio:"radio",range:"slider",button:"button",submit:"button",reset:"button",file:"file input",number:"spinbutton",search:"searchbox"},i=document.querySelectorAll("[data-ap-ref]"),f=0;f<i.length;f++)i[f].removeAttribute("data-ap-ref");var g=0,l=[];function m(t){return String(t||"").replace(/\s+/g," ").trim().slice(0,200)}function b(t){return JSON.stringify(t)}function T(t){if(t.hidden)return!0;var a=window.getComputedStyle(t);return a.display==="none"||a.visibility==="hidden"||a.opacity==="0"}function A(t){var a=t.getAttribute("aria-label")||t.getAttribute("title")||t.getAttribute("alt");if(!a&&t.id){var r=document.querySelector('label[for="'+t.id.replace(/"/g,'\\"')+'"]');r&&(a=r.textContent)}return!a&&(t.tagName==="INPUT"||t.tagName==="TEXTAREA")&&(a=t.getAttribute("placeholder")),a||(a=t.textContent),m(a)}function s(t){var a=t.getAttribute("role");return a||(/^H[1-6]$/.test(t.tagName)?"heading":t.tagName==="INPUT"?p[(t.type||"text").toLowerCase()]||"textbox":x[t.tagName]||null)}function h(t){return o[t.tagName]||t.hasAttribute("data-action")||t.getAttribute("tabindex")==="0"||/^(button|link|checkbox|tab|menuitem|switch|option)$/.test(t.getAttribute("role")||"")}function E(t,a){var r=["- "+a],d=A(t);d&&a!=="list"&&r.push(b(d));var e=[];if(/^H[1-6]$/.test(t.tagName)&&e.push("level="+t.tagName.charAt(1)),t.disabled&&e.push("disabled"),t.checked&&e.push("checked"),t.getAttribute("data-action")&&e.push("action="+t.getAttribute("data-action")),t.getAttribute("data-state")&&e.push("state="+t.getAttribute("data-state")),h(t)){var n="e"+ ++g;t.setAttribute("data-ap-ref",n),e.push("ref="+n)}var v=r.join(" ")+(e.length?" ["+e.join("] [")+"]":"");return(t.tagName==="INPUT"&&!/^(checkbox|radio|button|submit|reset|file)$/i.test(t.type)||t.tagName==="TEXTAREA")&&(v+=" value="+b(String(t.value||"").slice(0,200))),t.tagName==="SELECT"&&t.selectedIndex>=0&&(v+=" value="+b(m(t.options[t.selectedIndex].text))),v}function u(t,a){for(var r=t.firstChild;r;r=r.nextSibling){if(r.nodeType===3){var d=m(r.nodeValue);d&&l.push(new Array(a+1).join(" ")+"- text: "+b(d));continue}if(!(r.nodeType!==1||c[r.tagName]||T(r))){var e=s(r);if(e||h(r)){l.push(new Array(a+1).join(" ")+E(r,e||"generic")),(e==="list"||e==="listitem"||e==="dialog"||e==="region"||e==="group"||e==="tabpanel")&&u(r,a+1);continue}u(r,a+(r.getAttribute("data-state")||r.id?1:0))}}}return u(document.body,0),{title:document.title,url:location.href,lines:l,refs:g}}function y(o){function c(e){for(var n=e;n&&n.nodeType===1;n=n.parentElement){if(n.hidden)return!0;var v=window.getComputedStyle(n);if(v.display==="none"||v.visibility==="hidden")return!0}return!1}function x(e){for(var n=e;n&&n!==document.body;n=n.parentElement)if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|LABEL)$/.test(n.tagName)||n.hasAttribute("data-action")||/^(button|link|checkbox|tab|menuitem|switch|option)$/.test(n.getAttribute("role")||""))return n;return e}function p(e){if(!e)return"nothing";var n=String(e.textContent||"").replace(/\s+/g," ").trim().slice(0,60);return"<"+e.tagName.toLowerCase()+(e.id?"#"+e.id:"")+(e.className&&typeof e.className=="string"?"."+e.className.trim().split(/\s+/).join("."):"")+">"+(n?' "'+n+'"':"")}var i=null,f="";try{if(o.ref)f="ref "+o.ref,i=document.querySelector('[data-ap-ref="'+o.ref+'"]');else if(o.selector){f="selector "+o.selector;for(var g=document.querySelectorAll(o.selector),l=0;l<g.length&&!i;l++)c(g[l])||(i=g[l]);i||(i=g[0]||null)}else if(o.text){f="text "+JSON.stringify(o.text);for(var m=String(o.text).toLowerCase(),b=null,T=document.body.getElementsByTagName("*"),A=0;A<T.length;A++){var s=T[A];if(!/^(SCRIPT|STYLE|TEMPLATE)$/.test(s.tagName)){var h=String(s.textContent||"").toLowerCase(),E=[s.getAttribute("placeholder"),s.getAttribute("aria-label"),s.getAttribute("title"),s.getAttribute("alt"),typeof s.value=="string"?s.value:null].join(`
2
- `).toLowerCase();(h.indexOf(m)!==-1||E.indexOf(m)!==-1)&&!c(s)&&(b=s)}}i=b?x(b):null}}catch(e){return{error:"Invalid selector: "+e.message}}if(!i)return{found:!1,label:f};if(o.mark&&i.setAttribute("data-ap-target",o.mark),c(i))return{found:!0,visible:!1,label:f,element:p(i),tag:i.tagName,type:i.type||null};o.scroll!==!1&&i.scrollIntoView&&i.scrollIntoView({block:"center",inline:"center"});var u=i.getBoundingClientRect(),t=u.left+u.width/2,a=u.top+u.height/2,r=u.width&&u.height?document.elementFromPoint(t,a):null,d=r&&r!==i&&!i.contains(r)&&!(r.contains&&r.contains(i))?p(r):null;return{found:!0,visible:u.width>0&&u.height>0,disabled:!!i.disabled||i.getAttribute("aria-disabled")==="true",x:t,y:a,rect:{x:u.left,y:u.top,width:u.width,height:u.height},covered:d,label:f,element:p(i),tag:i.tagName,type:i.type||null}}function S(o){const c=String(o).replace(/^\[?ref=/,"").replace(/\]$/,"");if(!/^e\d+$/.test(c))throw new Error('Refs look like "e12" (from panel_snapshot).');return'[data-ap-ref="'+c+'"]'}module.exports={outlinePage:N,locateInPage:y,refSelector:S};
1
+ "use strict";function N(){for(var o={A:1,BUTTON:1,INPUT:1,SELECT:1,TEXTAREA:1,SUMMARY:1},c={SCRIPT:1,STYLE:1,TEMPLATE:1,NOSCRIPT:1,HEAD:1,META:1,LINK:1},x={A:"link",BUTTON:"button",SELECT:"combobox",TEXTAREA:"textbox",IMG:"img",UL:"list",OL:"list",LI:"listitem",DIALOG:"dialog",LABEL:"label",SUMMARY:"button"},v={checkbox:"checkbox",radio:"radio",range:"slider",button:"button",submit:"button",reset:"button",file:"file input",number:"spinbutton",search:"searchbox"},i=document.querySelectorAll("[data-ap-ref]"),f=0;f<i.length;f++)i[f].removeAttribute("data-ap-ref");var g=0,l=[];function m(t){return String(t||"").replace(/\s+/g," ").trim().slice(0,200)}function b(t){return JSON.stringify(t)}function T(t){if(t.hidden)return!0;var a=window.getComputedStyle(t);return a.display==="none"||a.visibility==="hidden"||a.opacity==="0"}function A(t){var a=t.getAttribute("aria-label")||t.getAttribute("title")||t.getAttribute("alt");if(!a&&t.id){var r=document.querySelector('label[for="'+t.id.replace(/"/g,'\\"')+'"]');r&&(a=r.textContent)}return!a&&(t.tagName==="INPUT"||t.tagName==="TEXTAREA")&&(a=t.getAttribute("placeholder")),a||(a=t.textContent),m(a)}function s(t){var a=t.getAttribute("role");return a||(/^H[1-6]$/.test(t.tagName)?"heading":t.tagName==="INPUT"?v[(t.type||"text").toLowerCase()]||"textbox":x[t.tagName]||null)}function h(t){return o[t.tagName]||t.hasAttribute("data-action")||t.getAttribute("tabindex")==="0"||/^(button|link|checkbox|tab|menuitem|switch|option)$/.test(t.getAttribute("role")||"")}function E(t,a){var r=["- "+a],d=A(t);d&&a!=="list"&&r.push(b(d));var e=[];if(/^H[1-6]$/.test(t.tagName)&&e.push("level="+t.tagName.charAt(1)),t.disabled&&e.push("disabled"),t.checked&&e.push("checked"),t.getAttribute("data-action")&&e.push("action="+t.getAttribute("data-action")),t.getAttribute("data-state")&&e.push("state="+t.getAttribute("data-state")),h(t)){var n="e"+ ++g;t.setAttribute("data-ap-ref",n),e.push("ref="+n)}var p=r.join(" ")+(e.length?" ["+e.join("] [")+"]":"");return(t.tagName==="INPUT"&&!/^(checkbox|radio|button|submit|reset|file)$/i.test(t.type)||t.tagName==="TEXTAREA")&&(p+=" value="+b(String(t.value||"").slice(0,200))),t.tagName==="SELECT"&&t.selectedIndex>=0&&(p+=" value="+b(m(t.options[t.selectedIndex].text))),p}function u(t,a){for(var r=t.firstChild;r;r=r.nextSibling){if(r.nodeType===3){var d=m(r.nodeValue);d&&l.push(new Array(a+1).join(" ")+"- text: "+b(d));continue}if(!(r.nodeType!==1||c[r.tagName]||T(r))){var e=s(r);if(e||h(r)){l.push(new Array(a+1).join(" ")+E(r,e||"generic")),(e==="list"||e==="listitem"||e==="dialog"||e==="region"||e==="group"||e==="tabpanel")&&u(r,a+1);continue}u(r,a+(r.getAttribute("data-state")||r.id?1:0))}}}return u(document.body,0),{title:document.title,url:location.href,lines:l,refs:g}}function y(o){function c(e){for(var n=e;n&&n.nodeType===1;n=n.parentElement){if(n.hidden)return!0;var p=window.getComputedStyle(n);if(p.display==="none"||p.visibility==="hidden")return!0}return!1}function x(e){for(var n=e;n&&n!==document.body;n=n.parentElement)if(/^(A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY|LABEL)$/.test(n.tagName)||n.hasAttribute("data-action")||/^(button|link|checkbox|tab|menuitem|switch|option)$/.test(n.getAttribute("role")||""))return n;return e}function v(e){if(!e)return"nothing";var n=String(e.textContent||"").replace(/\s+/g," ").trim().slice(0,60);return"<"+e.tagName.toLowerCase()+(e.id?"#"+e.id:"")+(e.className&&typeof e.className=="string"?"."+e.className.trim().split(/\s+/).join("."):"")+">"+(n?' "'+n+'"':"")}var i=null,f="";try{if(o.ref)f="ref "+o.ref,i=document.querySelector('[data-ap-ref="'+o.ref+'"]');else if(o.selector){f="selector "+o.selector;for(var g=document.querySelectorAll(o.selector),l=0;l<g.length&&!i;l++)c(g[l])||(i=g[l]);i||(i=g[0]||null)}else if(o.text){f="text "+JSON.stringify(o.text);for(var m=String(o.text).toLowerCase(),b=null,T=document.body.getElementsByTagName("*"),A=0;A<T.length;A++){var s=T[A];if(!/^(SCRIPT|STYLE|TEMPLATE)$/.test(s.tagName)){var h=String(s.textContent||"").toLowerCase(),E=[s.getAttribute("placeholder"),s.getAttribute("aria-label"),s.getAttribute("title"),s.getAttribute("alt"),typeof s.value=="string"?s.value:null].join(`
2
+ `).toLowerCase();(h.indexOf(m)!==-1||E.indexOf(m)!==-1)&&!c(s)&&(b=s)}}i=b?x(b):null}}catch(e){return{error:"Invalid selector: "+e.message}}if(!i)return{found:!1,label:f};if(o.mark&&i.setAttribute("data-ap-target",o.mark),c(i))return{found:!0,visible:!1,label:f,element:v(i),tag:i.tagName,type:i.type||null};o.scroll!==!1&&i.scrollIntoView&&i.scrollIntoView({block:"center",inline:"center"});var u=i.getBoundingClientRect(),t=u.left+u.width/2,a=u.top+u.height/2,r=u.width&&u.height?document.elementFromPoint(t,a):null,d=r&&r!==i&&!i.contains(r)&&!(r.contains&&r.contains(i))?v(r):null;return{found:!0,visible:u.width>0&&u.height>0,disabled:!!i.disabled||i.getAttribute("aria-disabled")==="true",x:t,y:a,rect:{x:u.left,y:u.top,width:u.width,height:u.height},covered:d,label:f,element:v(i),tag:i.tagName,type:i.type||null}}function S(o){const c=String(o).replace(/^\[?ref=/,"").replace(/\]$/,"");if(!/^e\d+$/.test(c))throw new Error('Refs look like "e12" (from `ap panel snapshot`).');return'[data-ap-ref="'+c+'"]'}module.exports={outlinePage:N,locateInPage:y,refSelector:S};
@@ -0,0 +1 @@
1
+ "use strict";class r extends Error{}module.exports={ToolError:r};
@@ -0,0 +1,3 @@
1
+ "use strict";const b=require("fs"),z=require("os"),y=require("path"),{ToolError:h}=require("../tool-error"),{captureFramesScript:F,hostAdapter:D}=require("../extendscript"),{isCompletePng:R,fitPng:_}=require("../png"),A=12,P={one:1920,several:960};async function S(r,s,c,e){let o=-1;for(;;){let t=null;try{t=b.readFileSync(r)}catch{t=null}const i=!!(t&&R(t));if(i&&(e||t.length===o))return t;if(o=i?t.length:-1,Date.now()>s)return i?t:null;await c(40)}}function j(r,s,c){return r==null?[]:(Array.isArray(r)?r:[r]).map(o=>{const t=Number(o);if(!Number.isFinite(t)||t<0||c&&!Number.isInteger(t))throw new h(s+" must be "+(c?"whole frame numbers":"seconds")+" from 0; got "+JSON.stringify(o)+".");return t})}function G(r){return r==null||r===""?null:typeof r=="number"?r:String(r)}function M(r){return Math.round(r*1e3)/1e3}module.exports=function(s){const c=s.ctx&&s.ctx.sleep||(e=>new Promise(o=>setTimeout(o,e)));return[{name:"comp_capture",async handler(e){const o=j(e.seconds,"seconds",!1).map(m=>({seconds:m})).concat(j(e.frames,"frames",!0).map(m=>({frame:m})));if(o.length>A)throw new h("Up to "+A+" times per run; got "+o.length+".");const t=await s.hostApp(e.panel);if(t!=="AEFT")throw new h("`ap comp capture` works in After Effects; the connected app is "+D(t).appName+".");const i=Math.min(Math.max(Number(e.timeoutMs)||6e4,1e3),3e5),u=b.mkdtempSync(y.join(z.tmpdir(),"ap-capture-"));try{const m=await s.hostEval(e.panel,F({comp:G(e.comp),at:o,dir:u,purge:e.purge!==!1,keep32:e.keep32===!0}),i,t);if(!m.ok)throw new h("Could not render the frames: "+m.error);const n=m.value,l=n&&n.frames||[],k=l.length>1,C=Number(e.maxSize)>0?Math.max(16,Math.round(Number(e.maxSize))):k?P.several:P.one,T=Date.now()+Math.min(i,3e4),N=[],E=[];for(let p=0;p<l.length;p++){const a=l[p],q=y.join(u,"frame-"+p+".png");let f=await S(q,T,c,a.waited===!0);if(!f){const x=y.join(u,"retry-"+p);b.mkdirSync(x);const w=await s.hostEval(e.panel,F({comp:n.id,at:[{frame:a.frame}],dir:x,purge:e.purge!==!1,keep32:e.keep32===!0}),i,t),g=w.ok&&w.value&&w.value.frames&&w.value.frames[0];g&&(f=await S(y.join(x,"frame-0.png"),Date.now()+Math.min(i,3e4),c,g.waited===!0),f&&typeof g.renderMs=="number"&&(a.renderMs=g.renderMs))}if(!f)throw new h("After Effects did not write frame "+a.frame+" ("+M(a.seconds)+" s) in time. Try again, or a longer --timeout-ms.");const d=_(f,C);N.push({type:"image",data:d.png.toString("base64"),mimeType:"image/png"}),E.push(p+1+". frame "+a.frame+" ("+M(a.seconds)+" s)"+(typeof a.renderMs=="number"?", rendered in "+a.renderMs+" ms":"")+(d.factor>1?", shown at 1/"+d.factor+" size ("+d.width+"x"+d.height+")":""))}return{content:[{type:"text",text:'Composition "'+n.comp+'" (id '+n.id+"), "+n.width+"x"+n.height+", "+M(n.frameRate)+" fps, "+M(n.duration)+" s, "+n.bitsPerChannel+" bpc project. "+(n.bitsPerChannel===32&&n.renderedBpc===16?"Rendered at 16 bpc (the project went back to 32 bpc right after): a 32-bpc PNG export comes out too dark, so these images show the 16-bpc render path, not the float one. ":n.bitsPerChannel===32?"WARNING: rendered at 32 bpc as asked; PNG export of 32-bpc renders comes out too dark, so judge brightness at 8 or 16 bpc. ":"")+(n.purged?"Caches purged first, so render times are uncached. ":"Caches kept (--no-purge); render times may be cached. ")+l.length+" image"+(k?"s":"")+":"+`
2
+ `+E.join(`
3
+ `)}].concat(N)}}finally{b.rmSync(u,{recursive:!0,force:!0})}}}]},module.exports.waitForPng=S,module.exports.MAX_FRAMES=A;
@@ -0,0 +1 @@
1
+ "use strict";const{ToolError:h}=require("../tool-error"),{wrapEval:j,hostAdapter:v,isAeScratchPath:y}=require("../extendscript"),{createHostTarget:_,bridgeApps:k,bridgePorts:A,projectOrNull:E,appNameOf:m}=require("../host-target"),{BRIDGE_TITLE:T,bridgeStatus:S,installDevBridge:x,removeDevBridge:P}=require("../../dev/bridge");function b(i){return i.hostTarget||(i.hostTarget=_(i)),i.hostTarget}function O(i){return async function(n){const r=await b(i).resolve(n);if(r.via==="bridge")return r.app;const o=r.project.settings.hosts[0].app;return await r.page.evaluate(()=>{try{return JSON.parse(window.__adobe_cep__.getHostEnvironment()).appName||null}catch{return null}})||o}}function N(i){const a=i.charAt(0).toUpperCase()+i.slice(1);return a+" returned nothing: its script engine did not run the script. "+a+" may be showing a dialog (an alert, a save prompt, Safe Mode or a crash report) or be busy. Ask the user to look at "+i+" and close the dialog, then try again. Never force-quit "+i+" to get out of this."}function C(i){return async function(n,r,o,e){const{page:t}=await b(i).resolve(n),s=e?m(e):"the host app",l=await t.evaluate(({source:f,ms:g})=>new Promise(u=>{if(!window.__adobe_cep__||!window.__adobe_cep__.evalScript){u({missing:!0});return}let d=!1;const p=setTimeout(()=>{d||(d=!0,u({timeout:!0}))},g);window.__adobe_cep__.evalScript(f,w=>{d||(d=!0,clearTimeout(p),u({result:w}))})}),{source:r,ms:o});if(l.missing)throw new h("This page has no CEP bridge (__adobe_cep__). Is it running inside After Effects or Premiere Pro?");if(l.timeout)throw new h(s.charAt(0).toUpperCase()+s.slice(1)+" did not answer within "+Math.round(o/1e3)+" s. It may be showing a dialog, rendering, or running a long loop. Ask the user to check "+s+"; the script may still finish.");const c=l.result;if(c===""||c===void 0||c===null)throw new h(N(s));if(c==="EvalScript error.")return{ok:!1,error:"ExtendScript syntax or evaluation error ("+s+" gives no details for syntax errors).",line:null};try{return JSON.parse(c)}catch{return{ok:!0,value:c}}}}module.exports=function(a){return[{name:"host_eval",async handler(n){const r=await a.hostApp(n.panel),o=v(r),e=j(String(n.code),{undo:o.undo&&n.undo!==!1}),t=Math.min(Math.max(Number(n.timeoutMs)||3e4,1e3),3e5),s=await a.hostEval(n.panel,e.script,t,r);if(!s.ok){const l=typeof s.line=="number"?s.line-e.lineOffset:null;throw new h("ExtendScript error in "+o.appName+(l&&l>0?" on line "+l:"")+": "+s.error)}return s.value===void 0?"null":JSON.stringify(s.value,null,2)}},{name:"host_scratch_project",async handler(n){const r=await a.hostApp(n.panel),o=v(r);if(!o.scratchClosesProject)return I(a,n,r,o);const e=await a.hostEval(n.panel,o.projectInfoScript(),15e3,r);if(!e.ok)throw new h("Could not read the open project: "+e.error);const t=e.value,s=t.path?t.path:t.items?"an untitled project with "+t.items+" item(s)":"an empty untitled project";if(r==="AEFT"&&y(t.path)&&!t.items)return"The open project is already an empty scratch project ("+t.path+"); use it.";if(t.unsaved&&!n.current)return{content:[{type:"text",text:"Nothing changed. The open project ("+s+") has unsaved changes. Ask the user, then run `ap host scratch save`"+(t.path?"":" (not possible: it was never saved; the user must save it in the app first)")+" or `ap host scratch discard`."}]};if(n.current==="save"&&t.unsaved&&!t.path)throw new h("The open project was never saved, so it cannot be saved without a dialog. Ask the user to save it (File > Save As), or to agree to discard it.");const l=t.unsaved?n.current:"save",c=await a.hostEval(n.panel,o.scratchProjectScript(l),6e4,r);if(!c.ok)throw new h("Could not open a scratch project: "+c.error);return(t.unsaved?l==="save"?"Saved and closed ":"Discarded changes and closed ":"Closed ")+s+". An empty scratch project is open"+(c.value&&c.value.path?" ("+c.value.path+")":"")+"."}},{name:"host_bridge",async handler(n){const r=n.action||"status";if(["status","install","remove"].indexOf(r)===-1)throw new h("action must be status, install or remove.");if(r==="remove"){const p=P(a.ctx);return p.removed?"Removed "+p.dir+". Apps that loaded it keep it until they quit.":"The dev bridge is not installed ("+p.dir+")."}let o=null;r==="install"&&(o=await x(a.ctx));const e=S(a.ctx);let t=null;try{t=E(a)}catch{t=null}const s=k(t),l=A(a),c={};for(const p of Object.keys(l)){const w=await a.panels.pageTitles(l[p]);c[m(p)]=!!(w&&w.indexOf(T)!==-1)}const f=s.filter(p=>c[m(p)]),g=s.map(m).join(" / ");let u;e.foreign?u=e.dir+" exists but was not created by AfterPresets; ask the user to move it, then install again.":e.installed?f.length&&o&&o.status==="updated"?u="Updated; ask the user to restart "+f.map(m).join(" and ")+" to load the new version (the old one keeps working until then).":f.length?u="Ready: host tools reach "+f.map(m).join(" and ")+" through the bridge.":u="Installed. "+g+" loads it at launch: if the app is open, ask the user to save their work and restart it once; then run `ap host bridge` again to confirm.":u="Not installed. Run `ap host bridge install`.";const d={installed:e.installed,upToDate:e.current,folder:e.dir,loadedIn:c,ports:Object.fromEntries(Object.keys(l).map(p=>[m(p),l[p]])),next:u};return o&&(d.change=o.status,o.debugModeFailures.length&&(d.debugModeWarnings=o.debugModeFailures)),d}}]};async function I(i,a,n,r){const o=await i.hostEval(a.panel,r.projectInfoScript(),15e3,n);if(!o.ok)throw new h("Could not read the open project: "+o.error);const e=o.value||{};if(e.path&&/AfterPresets scratch \d+\.prproj$/.test(e.path)&&!e.items&&!e.sequences)return"The active project is already an empty scratch project ("+e.path+"); use it.";const t=await i.hostEval(a.panel,r.scratchProjectScript(a.current==="save"?"save":"keep"),6e4,n);if(!t.ok)throw new h("Could not create a scratch project in "+r.appName+": "+t.error);const s=t.value||{};return((a.current==="save"&&e.path?"Saved "+e.path+". ":"")+"Created and opened an empty scratch project ("+s.path+"). "+(e.path?s.previousStillOpen?"The user's project "+e.path+" is still open in "+r.appName+" (Window menu or its project tab).":"Premiere Pro closed the user's project "+e.path+".":"")).trim()}module.exports.createHostEval=C,module.exports.createHostApp=O;
@@ -0,0 +1 @@
1
+ "use strict";const{ToolError:s}=require("../tool-error"),{quietContext:n}=require("../capture"),i=require("../../dev/native"),{projectInfoScript:c,isAeScratchPath:h}=require("../extendscript");module.exports=function(r){return[{name:"host_restart",async handler(){if((r.ctx.platform||process.platform)==="win32")throw new s("After Effects is not restarted automatically on Windows: ask the user to save their work and restart After Effects, then run `ap host bridge` until it says Ready.");let a=null;try{a=r.project()}catch{a=null}let e;try{const t=await r.hostEval(void 0,c(),15e3,"AEFT");if(e=t&&t.ok?t.value:null,!e)throw new Error(t&&t.error?t.error:"no answer")}catch(t){throw new s("Did not restart After Effects: could not read its project first ("+t.message+"). Ask the user to save their work and restart After Effects.")}if(e.unsaved&&e.items>0&&!h(e.path))throw new s("Did not restart After Effects: the open project "+(e.path?"("+e.path+") ":"(untitled) ")+"has unsaved changes. Ask the user to save their work and restart After Effects, or use `ap host scratch` first if the user agrees.");const o=await i.restartAfterEffects(n(r.ctx),a,{hostEval:r.hostEval});if(!o.restarted)throw new s(o.message);return o.message+" Wait until `ap host bridge` says Ready, then test with `ap host eval` and `ap comp capture`."}}]};
@@ -0,0 +1,7 @@
1
+ "use strict";const _=require("fs"),S=require("path"),{ToolError:s}=require("../tool-error"),{panelPorts:x}=require("../panels"),{isExpression:k,chooseFileScript:P}=require("../extendscript"),{hostAppNames:A}=require("../../targets"),{readDevStatus:E}=require("../../dev/session"),{outlinePage:j,locateInPage:w,refSelector:O}=require("../snapshot"),h=4e4;function m(l){const o=String(l);return o.length>h?o.slice(0,h)+`
2
+ \u2026 (`+(o.length-h)+" more characters cut)":o}function b(l){if(l.ref){try{O(l.ref)}catch(o){throw new s(o.message)}return{ref:String(l.ref).replace(/^\[?ref=/,"").replace(/\]$/,"")}}if(l.selector)return{selector:String(l.selector)};if(l.text)return{text:String(l.text)};throw new s("Pass ref (from `ap panel snapshot`), selector or text.")}async function y(l,o,c){const e=Object.assign(b(o),c||{}),n=Date.now()+3e3;for(;;){const t=await l.evaluate(w,e);if(t.error)throw new s(t.error);if(t.found&&t.visible){if(t.covered&&!(c&&c.ignoreCovered))throw new s("The element ("+t.element+") is covered by "+t.covered+".");return t}if(Date.now()>n)throw t.found?new s(t.element+" is hidden."):new s("Nothing matches "+t.label+"."+(o.ref?" Refs change with every snapshot; take a new `ap panel snapshot`.":""));await new Promise(a=>setTimeout(a,150))}}function v(l){return["(async () => {"," const __apValue = await (async () => {",k(l)?"return ("+l+`
3
+ );`:l," })();"," if (__apValue === undefined) return { type: 'undefined' };"," try { return { type: 'json', value: JSON.parse(JSON.stringify(__apValue)) }; }"," catch (e) { return { type: 'string', value: String(__apValue) }; }","})()"].join(`
4
+ `)}function g(l,o){if(!Array.isArray(o)||!o.length)throw new s("Pass paths: one or more files.");return o.map(c=>{const e=S.resolve(l.projectRoot(),String(c));if(!_.existsSync(e))throw new s("File not found: "+e);return e})}module.exports=function(o){const c=async e=>(await o.panels.connect(o.project(),e.panel)).page;return[{name:"panel_list",async handler(){const e=o.project(),n=await Promise.all(x(e).map(async a=>Object.assign({},a,{reachable:await o.panels.reachable(a.port)}))),t=E(e);return{panels:n,devBuild:t&&t.lastBuild?{ok:t.lastBuild.ok,at:t.lastBuild.at,error:t.lastBuild.error||null}:null,note:n.some(a=>a.reachable)?void 0:"No panel is reachable. Start dev (`ap dev --background`), then ask the user to open the panel in "+A(e.settings)+" (Window > Extensions)."}}},{name:"panel_snapshot",async handler(e){const t=await(await c(e)).evaluate(j);return m("Panel "+(e.panel||"(first)")+" \xB7 "+t.title+`
5
+ `+(t.lines.join(`
6
+ `)||"(nothing visible)"))}},{name:"panel_screenshot",async handler(e){const n=await c(e);let t;return(e.ref||e.selector||e.text)&&(t=(await y(n,e,{ignoreCovered:!0})).rect),{content:[{type:"image",data:(await n.screenshot(t?{type:"png",clip:t}:{type:"png"})).toString("base64"),mimeType:"image/png"}]}}},{name:"panel_click",async handler(e){const n=await c(e),t=await y(n,e);if(t.disabled)throw new s(t.element+" is disabled.");return await n.mouse.click(t.x,t.y,{clickCount:e.double?2:1}),"Clicked "+t.element+"."}},{name:"panel_type",async handler(e){const n=await c(e),t=Object.assign({},e);delete t.text,e.into&&(t.text=e.into);const a=await y(n,t,{mark:"type"});if(a.disabled)throw new s(a.element+" is disabled.");if(!await n.evaluate(()=>{const i=document.querySelector('[data-ap-target="type"]');return i?(i.removeAttribute("data-ap-target"),i.focus(),typeof i.select=="function"?i.select():i.isContentEditable&&document.execCommand("selectAll",!1,null),document.activeElement===i):!1}))throw new s(a.element+" cannot take text.");return String(e.text)?await n.keyboard.insertText(String(e.text)):await n.keyboard.press("Backspace"),await n.evaluate(()=>document.activeElement&&document.activeElement.dispatchEvent(new Event("change",{bubbles:!0}))),e.submit&&await n.keyboard.press("Enter"),"Typed into "+a.element+"."}},{name:"panel_press",async handler(e){return await(await c(e)).keyboard.press(String(e.key)),"Pressed "+e.key+"."}},{name:"panel_wait_for",async handler(e){const n=await c(e),t=Math.min(Math.max(Number(e.timeoutMs)||5e3,100),6e4);if(!e.text&&!e.selector)throw new s("Pass text or selector.");const a=e.selector?{selector:String(e.selector),scroll:!1}:{text:String(e.text),scroll:!1},u=Date.now()+t;for(;;){const i=await n.evaluate(w,a);if(i.error)throw new s(i.error);const d=i.found&&i.visible;if(e.gone?!d:d)return(e.gone?"Gone: ":"Visible: ")+(e.selector||e.text);if(Date.now()>u)throw new s("Timed out after "+t+" ms waiting for "+(e.selector||JSON.stringify(e.text))+(e.gone?" to disappear.":" to appear."));await new Promise(r=>setTimeout(r,100))}}},{name:"panel_upload",async handler(e){const n=g(o,e.paths),t=await c(e),a=await t.evaluate(w,Object.assign(b(e),{mark:"upload",scroll:!1}));if(a.error)throw new s(a.error);if(!a.found)throw new s("Nothing matches "+a.label+".");if(a.tag!=="INPUT"||a.type!=="file")throw new s(a.element+' is not an <input type="file">. If a button opens a native dialog, use `ap panel choose-file`.');const u=await t.evaluateHandle(()=>{const i=document.querySelector('[data-ap-target="upload"]');return i&&i.removeAttribute("data-ap-target"),i});return await u.asElement().setInputFiles(n),await u.dispose(),"Set "+n.length+" file(s) on "+a.element+": "+n.join(", ")}},{name:"panel_choose_file",async handler(e){const n=g(o,e.paths),a=await(await c(e)).evaluate(({files:d})=>{const r=window.cep&&window.cep.fs;if(!r)return!1;const p=r.__apDialogs||(r.__apDialogs={a:r.showOpenDialog,b:r.showOpenDialogEx}),f=function(){return r.showOpenDialog=p.a,r.showOpenDialogEx=p.b,{err:0,data:d.slice()}};return p.a&&(r.showOpenDialog=f),p.b&&(r.showOpenDialogEx=f),!0},{files:n}),u=await o.hostEval(e.panel,P(n,!!e.folder),1e4),i=u.ok&&u.value&&u.value.installed;if(!a&&!i)throw new s("Could not replace the file dialogs in this panel or in the host app."+(u.ok?"":" "+u.error));return"The next "+(e.folder?"folder":"file")+" dialog returns "+n.join(", ")+" (panel cep.fs: "+(a?"yes":"no")+", ExtendScript: "+(i?"yes":"no")+")."}},{name:"panel_logs",async handler(e){const{page:n,logs:t}=await o.panels.connect(o.project(),e.panel),a=Math.min(Math.max(Number(e.limit)||100,1),500),d=(await n.evaluate(r=>{const p=window.__apDevLogs;if(!Array.isArray(p))return null;const f=p.slice();return r&&(p.length=0),f},!!e.clear).catch(()=>null)||t).filter(r=>!e.errorsOnly||r.level==="error"||r.level==="warning").slice(-a);return e.clear&&(t.length=0),d.length?m(d.map(r=>r.at.slice(11,19)+" "+r.level.padEnd(7)+" "+r.text).join(`
7
+ `)):"No console messages yet."}},{name:"panel_reload",async handler(e){const n=await c(e);return await n.reload({waitUntil:"load"}),"Reloaded "+await n.title()+" ("+n.url()+")."}},{name:"panel_eval",async handler(e){const n=await(await c(e)).evaluate(v(String(e.code)));return n.type==="undefined"?"undefined":m(n.type==="json"?JSON.stringify(n.value,null,2):n.value)}},{name:"license_simulate",async handler(e){const n=await c(e),t=String(e.status),a=await n.evaluate(u=>typeof AP>"u"||!AP.__simulate?{missing:!0}:{ok:AP.__simulate(u==="off"?!1:u),state:AP.license&&AP.license.state?AP.license.state.status:null,statuses:AP.__simulate()},t);if(a.missing)throw new s("AP is not loaded in this panel. Is it an AfterPresets dev build that called AP.boot?");if(!a.ok)throw new s("Could not simulate "+JSON.stringify(t)+". Licensing must be on in this panel and the build must be a dev build. Statuses: "+(a.statuses||[]).join(", ")+", off.");return t==="off"?"Simulation ended; real status: "+a.state+".":"Showing "+t+". Take a screenshot, then run `ap panel license off`."}}]},module.exports.pageScript=v;
@@ -0,0 +1,2 @@
1
+ "use strict";const{createRedactor:E}=require("./redact"),{createPanelConnections:g}=require("./panels"),{readCredentials:w}=require("../auth/credentials"),{loadProject:y,findProjectRoot:A}=require("../project/project"),{ToolError:u}=require("./tool-error"),R=["panel","host","capture","native"],j=["CliError","ApiError","UsageError"];function c(t,i){const e={content:[{type:"text",text:String(t)}]};return i&&(e.isError=!0),e}function m(t){return t==null?c("Done."):typeof t=="string"?c(t):Array.isArray(t.content)?t:c(JSON.stringify(t,null,2))}function q(t,i){const e=i||{},s={ctx:t,panels:e.panels||g({fetch:e.fetch,chromium:e.chromium}),bridgePorts:e.bridgePorts||null,projectRoot(){const r=A(t.cwd);if(!r)throw new u("There is no AfterPresets project in "+t.cwd+". Run this in the project folder, or create one with `ap init`.");return r},project(){return s.projectRoot(),y(t)}},l=require("./tools/host");s.hostEval=e.hostEval||l.createHostEval(s),s.hostApp=e.hostApp||(e.hostEval?async()=>"AEFT":l.createHostApp(s));const a=new Map;R.forEach(r=>require("./tools/"+r)(s).forEach(o=>a.set(o.name,o)));const f=E(()=>{try{const r=w(t);return r?[r.token]:[]}catch{return[]}}),p=r=>Object.assign({},r,{content:r.content.map(o=>o.type==="text"?Object.assign({},o,{text:f(o.text)}):o)});async function d(r,o){const h=a.get(r);if(!h)throw new Error("Unknown tool: "+r);try{return p(m(await h.handler(o||{})))}catch(n){return!(n instanceof u||j.indexOf(n&&n.name)!==-1)&&e.onUnexpectedError&&e.onUnexpectedError(n),p(c((n&&n.message?n.message:String(n))+(n&&n.hint?`
2
+ `+n.hint:""),!0))}}return{call:d,tools:a,env:s,close:()=>s.panels.closeAll()}}module.exports={createAgentTools:q,ToolError:u};
@@ -1 +1 @@
1
- "use strict";function n(e,s){const a=s&&s.webBase?s.webBase:"https://afterpresets.com",t=e.details||{};switch(e.code){case"push_quota_exceeded":return{message:"You have used all production pushes for this month.",hint:"Test-channel pushes and rollbacks do not count. Push to test with `--channel test`, wait for the next UTC month, or upgrade to Creator or Studio: "+a+"/membership"};case"version_not_greater":return{message:"This version is not greater than every existing release.",hint:"Check `ap releases list`, then push again with a larger --bump."};case"runtime_retired":return{message:"The @afterpresets/runtime version in this build has been retired.",hint:"Update it with `ap upgrade`, test with `ap dev`, and push again. Published releases keep working."};case"unauthorized":case"invalid_token":case"token_revoked":return{message:"Your CLI login is no longer valid.",hint:"Run `ap login` again."};case"forbidden":case"not_owner":return{message:"Your account does not own this extension.",hint:"Check that you are logged in as the right account with `ap whoami`."};case"not_found":case"product_not_found":return{message:e.serverMessage||"Not found.",hint:"Check the bundle ID in afterpresets.json and `ap whoami`."};case"expired_token":return{message:"The login request expired before it was approved.",hint:"Run `ap login` again."};case"slug_taken":case"slug_conflict":return{message:e.serverMessage||"That slug is already used by one of your extensions.",hint:"Choose a different slug."};case"tester_limit":case"tester_limit_reached":return{message:"An extension can have at most 10 testers.",hint:"Remove a tester with `ap testers remove <email>` first."};case"payload_too_large":return{message:"The bundle is larger than 200 MB.",hint:"Remove unused assets from the asset folders."};case"network_error":return{message:e.serverMessage,hint:"Check your connection, or AP_API_BASE when testing locally."};default:return{message:e.serverMessage||"The AfterPresets API returned HTTP "+e.status+".",hint:t.manageDevicesUrl?"Manage devices: "+t.manageDevicesUrl:null}}}module.exports={describeApiError:n};
1
+ "use strict";function n(e,s){const a=s&&s.webBase?s.webBase:"https://afterpresets.com",t=e.details||{};switch(e.code){case"push_quota_exceeded":return{message:"You have used all production pushes for this month.",hint:"Test-channel pushes and rollbacks do not count. Push to test with `--channel test`, wait for the next UTC month, or upgrade to Creator or Studio: "+a+"/membership"};case"version_not_greater":return{message:"This version is not greater than every existing release.",hint:"Check `ap releases list`, then push again with a larger --bump."};case"runtime_retired":return{message:"The @afterpresets/runtime version in this build has been retired.",hint:"Update it with `ap upgrade`, test with `ap dev`, and push again. Published releases keep working."};case"unauthorized":case"invalid_token":case"token_revoked":return{message:"Your CLI login is no longer valid.",hint:"Run `ap login` again."};case"forbidden":case"not_owner":return{message:"Your account does not own this extension.",hint:"Check that you are logged in as the right account with `ap whoami`."};case"not_found":case"product_not_found":return{message:e.serverMessage||"Not found.",hint:"Check the bundle ID in afterpresets.json and `ap whoami`."};case"expired_token":return{message:"The login request expired before it was approved.",hint:"Run `ap login` again."};case"slug_taken":case"slug_conflict":return{message:e.serverMessage||"That slug is already used by one of your extensions.",hint:"Choose a different slug."};case"tester_limit":case"tester_limit_reached":return{message:e.serverMessage||"You've reached your plan's tester limit.",hint:"Remove a tester with `ap testers remove <email>`, or upgrade your plan on afterpresets.com/membership."};case"payload_too_large":return{message:"The bundle is larger than 200 MB.",hint:"Remove unused assets from the asset folders."};case"network_error":return{message:e.serverMessage,hint:"Check your internet connection. AI agents: your sandbox may be blocking the internet; ask the user to allow this command to run outside the sandbox. (When testing locally, check AP_API_BASE.)"};default:return{message:e.serverMessage||"The AfterPresets API returned HTTP "+e.status+".",hint:t.manageDevicesUrl?"Manage devices: "+t.manageDevicesUrl:null}}}module.exports={describeApiError:n};
@@ -1,9 +1,10 @@
1
- "use strict";const l=require("fs"),u=require("path"),w=require("../config"),{generateManifest:F}=require("../project/manifest"),{bundlePanel:D,assetUrl:E}=require("./bundle"),{concatJsx:k}=require("./jsx"),{loadRuntime:A,concatFiles:x}=require("./runtime"),{copyAssets:B}=require("./assets"),{processIndexHtml:K}=require("./html"),{debugFileXml:O,debugPorts:R}=require("../dev/debug-file"),{CliError:S}=require("../errors"),{projectTargets:J}=require("../targets"),I="src";function q(e){const n=I+"/panels/"+e;return{dir:n,html:n+"/index.html",js:n+"/main.js"}}function P(e,n){return u.join(e,n.split("/").join(u.sep))}function L(e){l.mkdirSync(e,{recursive:!0}),l.readdirSync(e).forEach(n=>l.rmSync(u.join(e,n),{recursive:!0,force:!0}))}function N(e,n,r,s,a){const t=w.webBase(e),o=w.signingPublicKey(e);if(!o&&!s.dev)throw new S("No release signing public key is configured.",{hint:"Set AP_SIGNING_PUBLIC_KEY or run `ap config set signing-public-key <file-or-pem>`. The production key is not yet embedded in this CLI."});return{bundleId:n.settings.bundleId,panelId:r.id,version:s.version,apiBase:s.apiBase||w.apiBase(e,null),publicKey:o,name:n.settings.name||void 0,productUrl:n.settings.listingUrl||t,manageDevicesUrl:t+"/settings/extensions",dev:!!s.dev,runtimeVersion:a}}function y(e){return JSON.stringify(String(e)).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/<\/(script)/gi,"<\\/$1")}function _(e){return e.trim()?["(function () {",' var style = document.createElement("style");',' style.setAttribute("data-ap", "bundle");'," style.textContent = "+y(e)+";"," (document.head || document.documentElement).appendChild(style);","}());"].join(`
1
+ "use strict";const l=require("fs"),a=require("path"),w=require("../config"),{generateManifest:P}=require("../project/manifest"),{bundlePanel:D,assetUrl:_}=require("./bundle"),{concatJsx:F}=require("./jsx"),{loadRuntime:L,concatFiles:x}=require("./runtime"),{copyAssets:O}=require("./assets"),{processIndexHtml:R}=require("./html"),{debugFileXml:A,debugPorts:B}=require("../dev/debug-file"),{CliError:S}=require("../errors"),{projectTargets:K}=require("../targets"),I="src";function C(e){const n=I+"/panels/"+e;return{dir:n,html:n+"/index.html",js:n+"/main.js"}}function k(e,n){return a.join(e,n.split("/").join(a.sep))}function J(e){l.mkdirSync(e,{recursive:!0}),l.readdirSync(e).forEach(n=>l.rmSync(a.join(e,n),{recursive:!0,force:!0}))}function N(e,n,s,r,c){const t=w.webBase(e),o=w.signingPublicKey(e);if(!o&&!r.dev)throw new S("No release signing public key is configured.",{hint:"Set AP_SIGNING_PUBLIC_KEY or run `ap config set signing-public-key <file-or-pem>`. The production key is not yet embedded in this CLI."});return{bundleId:n.settings.bundleId,panelId:s.id,version:r.version,apiBase:r.apiBase||w.apiBase(e,null),publicKey:o,name:n.settings.name||void 0,productUrl:n.settings.listingUrl||t,manageDevicesUrl:t+"/settings/extensions",dev:!!r.dev,runtimeVersion:c}}function h(e){return JSON.stringify(String(e)).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/<\/(script)/gi,"<\\/$1")}function U(e){return e.trim()?["(function () {",' var style = document.createElement("style");',' style.setAttribute("data-ap", "bundle");'," style.textContent = "+h(e)+";"," (document.head || document.documentElement).appendChild(style);","}());"].join(`
2
2
  `):""}function M(e){return e.trim()?`(function () {
3
- document.body.innerHTML = `+y(e)+`;
4
- }());`:""}function C(e){return["/* ---- ap dev live reload (dev builds only) ---- */","(function () {"," var BUILD = "+y(e)+";",' var KEY = "ap-dev-reloaded-for";',' if (typeof require !== "function" || !window.AP || !AP.paths) return;',' var fs = require("fs");',' var stamp = require("path").join(AP.paths.extension(), ".ap-dev-build");'," var warned = null;"," var timer = setInterval(function () {"," var id, last = null;",' try { id = String(fs.readFileSync(stamp, "utf8")).trim(); } catch (e) { return; }'," if (!id || id === BUILD) return;"," try { last = window.sessionStorage.getItem(KEY); } catch (e) { last = null; }"," if (last === id) {",' if (warned !== id) { warned = id; console.warn("ap dev: this page is not build " + id + " (two builds overlapped?). Save a file to rebuild; not reloading again for this build."); }'," return;"," }"," try { window.sessionStorage.setItem(KEY, id); } catch (e) { /* reload anyway */ }"," clearInterval(timer);"," window.location.reload();"," }, 400);","}());"].join(`
5
- `)}async function U(e,n,r,s,a,t,o,c){const d=n.root,i=q(r.id),g=P(d,i.html);if(!l.existsSync(g))throw new S("Missing "+i.html+".",{hint:"Create it, or run `ap add panel "+r.id+"`."});const f=K(l.readFileSync(g,"utf8"),i.html,i.js,v=>E(d,n.settings,g,v));if(f.errors.length)throw new S(f.errors.join(`
6
- `));if(c.push.apply(c,f.warnings),!l.existsSync(P(d,i.js)))throw new S("Missing "+i.js+".",{hint:"It starts the panel with AP.boot({ start })."});const m=await D(d,i.js,n.settings),b=N(e,n,r,t,s.version),j=s.files.css.length?x(s.files.css)+`
7
- `:"",h=t.dev?2:0,p=u.join(o,"panels",r.id);return l.mkdirSync(p,{recursive:!0}),l.writeFileSync(u.join(p,"index.html"),f.shell),l.writeFileSync(u.join(p,"main.js"),["/* Built by the AfterPresets CLI. Edit the source files, not this bundle. */","var AP_CONFIG = "+JSON.stringify(b,null,h)+";","var AP_JSX = "+Y(a)+";","/* ---- styles (imported by "+i.js+") ---- */",_(j+m.css+`
8
- `),"/* ---- markup ("+i.html+") ---- */",M(f.body),"/* ---- @afterpresets/runtime ---- */",x(s.files.js),";","/* ---- developer code ("+i.js+" and its imports) ---- */",m.js,t.liveReload?C(t.buildId):"",""].join(`
9
- `)),{inputs:m.inputs,publicKey:b.publicKey}}function X(e){return"{ type: "+y(e.type)+", code: "+y(e.code)+" }"}function Y(e){return"{ "+Object.keys(e.hosts).map(n=>y(n)+": "+X(e.hosts[n])).join(", ")+" }"}function G(e,n,r,s,a){const t=k(e.root,n.files.jsx,a);if(r.dev)return{type:"jsx",code:t.source,files:t.files};const c=(r.compileJsx||require("./jsxbin").compileJsxbin)(t.source,{fileName:u.join(s,"jsx","main.jsx"),lineMap:t.lineMap});return{type:"jsxbin",code:String(c).trim(),files:t.files}}function H(e,n,r,s){const a={},t=[];return J(e.settings).filter(o=>o.platform==="cep").forEach(o=>{const c=G(e,n,r,s,o.jsxDir);a[o.host]={type:c.type,code:c.code},c.files.forEach(d=>t.indexOf(d)===-1&&t.push(d))}),{hosts:a,files:t.sort()}}async function T(e,n,r){const s=!!r.dev,a=r.version||n.version,t=s?Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8):null,o=Object.assign({},r,{dev:s,version:a,buildId:t,liveReload:s&&r.liveReload!==!1}),c=[],d=A(e,n.root),i=r.outDir;L(i);const g=H(n,d,o,i),f={};let m=!1;for(const p of n.panels){const v=await U(e,n,p,d,g,o,i,c);f[p.id]={inputs:v.inputs},v.publicKey||(m=!0)}m&&c.push("No signing public key is set; update signature checks cannot run in this dev build.");const b=g.files;l.mkdirSync(u.join(i,"CSXS"),{recursive:!0}),l.writeFileSync(u.join(i,"CSXS","manifest.xml"),F(n.settings,n.panels,a));const j=B(n.root,i,n.settings),h=R(n.panels,w.projectDebugPort(n.settings));return s&&l.writeFileSync(u.join(i,".debug"),O(h,n.settings.hosts.map(p=>p.app))),o.liveReload&&l.writeFileSync(u.join(i,".ap-dev-build"),t),{outDir:i,version:a,runtimeVersion:d.version,warnings:c,debugPorts:h,files:{panels:f,jsx:b,assets:j}}}function V(e){return u.join(e.root,"dist",e.settings.bundleId)}function $(e){return u.join(e.root,"dist-dev",e.settings.bundleId)}module.exports={buildProject:T,productionOutDir:V,devOutDir:$,panelSources:q,SRC_DIR:I,__liveReloadClient:C};
3
+ document.body.innerHTML = `+h(e)+`;
4
+ }());`:""}function q(e){return["/* ---- ap dev live reload (dev builds only) ---- */","(function () {"," var BUILD = "+h(e)+";",' var KEY = "ap-dev-reloaded-for";',' if (typeof require !== "function" || !window.AP || !AP.paths) return;',' var fs = require("fs");',' var stamp = require("path").join(AP.paths.extension(), ".ap-dev-build");'," var warned = null;"," var timer = setInterval(function () {"," var id, last = null;",' try { id = String(fs.readFileSync(stamp, "utf8")).trim(); } catch (e) { return; }'," if (!id || id === BUILD) return;"," try { last = window.sessionStorage.getItem(KEY); } catch (e) { last = null; }"," if (last === id) {",' if (warned !== id) { warned = id; console.warn("ap dev: this page is not build " + id + " (two builds overlapped?). Save a file to rebuild; not reloading again for this build."); }'," return;"," }"," try { window.sessionStorage.setItem(KEY, id); } catch (e) { /* reload anyway */ }"," clearInterval(timer);"," window.location.reload();"," }, 400);","}());"].join(`
5
+ `)}function E(){return["/* ---- ap dev console recorder (dev builds only) ---- */","(function () {"," if (window.__apDevLogs) return;"," var logs = window.__apDevLogs = [];"," function text(args) {"," var parts = [];"," for (var i = 0; i < args.length; i++) {"," var a = args[i];",' if (typeof a === "string") parts.push(a);'," else if (a instanceof Error) parts.push(a.stack || String(a));"," else { try { parts.push(JSON.stringify(a)); } catch (e) { parts.push(String(a)); } }"," }",' return parts.join(" ");'," }"," function record(level, message) {"," logs.push({ at: new Date().toISOString(), level: level, text: String(message).slice(0, 4000) });"," if (logs.length > 500) logs.splice(0, logs.length - 500);"," }",' ["log", "info", "warn", "error", "debug"].forEach(function (level) {'," var original = console[level];",' if (typeof original !== "function") return;'," console[level] = function () {",' try { record(level === "warn" ? "warning" : level, text(arguments)); } catch (e) { /* never break logging */ }'," return original.apply(console, arguments);"," };"," });",' window.addEventListener("error", function (e) { record("error", "Uncaught " + (e.error && e.error.stack ? e.error.stack : e.message)); });',' window.addEventListener("unhandledrejection", function (e) { var r = e.reason; record("error", "Unhandled rejection: " + (r && r.stack ? r.stack : String(r))); });',' record("info", "[page loaded] " + window.location.href);',"}());"].join(`
6
+ `)}async function X(e,n,s,r,c,t,o,u){const d=n.root,i=C(s.id),p=k(d,i.html);if(!l.existsSync(p))throw new S("Missing "+i.html+".",{hint:"Create it, or run `ap add panel "+s.id+"`."});const f=R(l.readFileSync(p,"utf8"),i.html,i.js,b=>_(d,n.settings,p,b));if(f.errors.length)throw new S(f.errors.join(`
7
+ `));if(u.push.apply(u,f.warnings),!l.existsSync(k(d,i.js)))throw new S("Missing "+i.js+".",{hint:"It starts the panel with AP.boot({ start })."});const v=await D(d,i.js,n.settings),m=N(e,n,s,t,r.version),j=r.files.css.length?x(r.files.css)+`
8
+ `:"",y=t.dev?2:0,g=a.join(o,"panels",s.id);return l.mkdirSync(g,{recursive:!0}),l.writeFileSync(a.join(g,"index.html"),f.shell),l.writeFileSync(a.join(g,"main.js"),["/* Built by the AfterPresets CLI. Edit the source files, not this bundle. */",t.dev?E():"","var AP_CONFIG = "+JSON.stringify(m,null,y)+";","var AP_JSX = "+G(c)+";","/* ---- styles (imported by "+i.js+") ---- */",U(j+v.css+`
9
+ `),"/* ---- markup ("+i.html+") ---- */",M(f.body),"/* ---- @afterpresets/runtime ---- */",x(r.files.js),";","/* ---- developer code ("+i.js+" and its imports) ---- */",v.js,t.liveReload?q(t.buildId):"",""].join(`
10
+ `)),{inputs:v.inputs,publicKey:m.publicKey}}function Y(e){return"{ type: "+h(e.type)+", code: "+h(e.code)+" }"}function G(e){return"{ "+Object.keys(e.hosts).map(n=>h(n)+": "+Y(e.hosts[n])).join(", ")+" }"}function H(e,n,s,r,c){const t=F(e.root,n.files.jsx,c);if(s.dev)return{type:"jsx",code:t.source,files:t.files};const u=(s.compileJsx||require("./jsxbin").compileJsxbin)(t.source,{fileName:a.join(r,"jsx","main.jsx"),lineMap:t.lineMap});return{type:"jsxbin",code:String(u).trim(),files:t.files}}function T(e,n,s,r){const c={},t=[];return K(e.settings).filter(o=>o.platform==="cep").forEach(o=>{const u=H(e,n,s,r,o.jsxDir);c[o.host]={type:u.type,code:u.code},u.files.forEach(d=>t.indexOf(d)===-1&&t.push(d))}),{hosts:c,files:t.sort()}}async function V(e,n,s){const r=!!s.dev,c=s.version||n.version,t=r?Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8):null,o=Object.assign({},s,{dev:r,version:c,buildId:t,liveReload:r&&s.liveReload!==!1}),u=[],d=L(e,n.root),i=s.outDir;J(i);const p=T(n,d,o,i),f={};let v=!1;for(const g of n.panels){const b=await X(e,n,g,d,p,o,i,u);f[g.id]={inputs:b.inputs},b.publicKey||(v=!0)}v&&u.push("No signing public key is set; update signature checks cannot run in this dev build.");const m=p.files;l.mkdirSync(a.join(i,"CSXS"),{recursive:!0}),l.writeFileSync(a.join(i,"CSXS","manifest.xml"),P(n.settings,n.panels,c));const j=O(n.root,i,n.settings),y=B(n.panels,w.projectDebugPort(n.settings));return r&&l.writeFileSync(a.join(i,".debug"),A(y,n.settings.hosts.map(g=>g.app))),o.liveReload&&l.writeFileSync(a.join(i,".ap-dev-build"),t),{outDir:i,version:c,runtimeVersion:d.version,warnings:u,debugPorts:y,files:{panels:f,jsx:m,assets:j}}}function $(e){return a.join(e.root,"dist",e.settings.bundleId)}function z(e){return a.join(e.root,"dist-dev",e.settings.bundleId)}module.exports={buildProject:V,productionOutDir:$,devOutDir:z,panelSources:C,SRC_DIR:I,__liveReloadClient:q,__devConsoleRecorder:E};
@@ -1,3 +1,3 @@
1
- "use strict";const l=require("fs"),m=require("path"),{processIndexHtml:L}=require("../build/html"),{panelSources:q,SRC_DIR:b}=require("../build/build"),{bundlePanel:T,assetUrl:k}=require("../build/bundle"),{JSX_DIR:x,jsxDirFiles:F,hostDirOf:I}=require("../build/jsx"),{TARGETS:R,projectTargets:v}=require("../targets"),j=["signed_out","signing_in","checking","active","not_owned","refunded","offline_grace","offline_expired","error"],O=/\blicense\s*:\s*(?:true\b|\{)/,B=/\bAP\s*\.\s*boot\s*\(/;function E(s){if(!l.existsSync(s))return[];const e=[];return l.readdirSync(s,{withFileTypes:!0}).forEach(n=>{const o=m.join(s,n.name);n.isDirectory()?e.push.apply(e,E(o)):n.isFile()&&e.push(o)}),e}function D(s){let e="",n=0,o=null;for(;n<s.length;){const i=s[n],f=s[n+1];if(o){if(e+=i,i==="\\"){e+=f||"",n+=2;continue}i===o&&(o=null),n++;continue}if(i==='"'||i==="'"||i==="`"){o=i,e+=i,n++;continue}if(i==="/"&&f==="/"){for(;n<s.length&&s[n]!==`
2
- `;)n++;continue}if(i==="/"&&f==="*"){const u=s.indexOf("*/",n+2);n=u===-1?s.length:u+2;continue}e+=i,n++}return e}function N(s,e){return m.relative(s,e).split(m.sep).join("/")}function d(s,e){return m.join(s,e.split("/").join(m.sep))}function P(s){const e=D(s),n=O.test(e);return{boots:B.test(e),licensed:n,rendersLicense:/\brenderLicense\b/.test(e),browserStorage:/\b(localStorage|sessionStorage|indexedDB)\b/.test(e),missingStatuses:j.filter(o=>!new RegExp("[\"'`]"+o+"[\"'`]").test(e))}}async function $(s){const e=s.root,n=[],o=[],i=(t,r,h)=>t.push({code:r,message:h}),f={},u=[];for(const t of s.panels){const r=q(t.id);f[r.html]=!0;const h={id:t.id,boots:!1,licensed:!1};if(u.push(h),!l.existsSync(d(e,r.dir))){i(n,"missing_panel",'afterpresets.json lists panel "'+t.id+'" but '+r.dir+"/ does not exist. Run `ap add panel "+t.id+"` or remove it from afterpresets.json.");continue}if([r.html,r.js].forEach(a=>{l.existsSync(d(e,a))||i(n,"missing_entry","Missing "+a+".")}),l.existsSync(d(e,r.html))){const a=d(e,r.html),w=L(l.readFileSync(a,"utf8"),r.html,r.js,g=>k(e,s.settings,a,g));w.errors.forEach(g=>i(n,"index_html",g)),w.warnings.forEach(g=>i(o,"index_html",g))}if(!l.existsSync(d(e,r.js)))continue;let p;try{p=await T(e,r.js,s.settings)}catch(a){i(n,"bundle_failed",a.message);continue}p.inputs.forEach(a=>f[a]=!0);const A=p.inputs.filter(a=>/\.(js|html)$/i.test(a)&&!/(^|\/)node_modules\//.test(a)).map(a=>l.readFileSync(d(e,a),"utf8")).join(`
3
- `),c=P(A);h.boots=c.boots,h.licensed=c.licensed,c.boots||i(n,"missing_boot",'Panel "'+t.id+'" never calls AP.boot(...). Start the panel from AP.boot({ start: ... }) in '+r.js+"."),c.browserStorage&&i(o,"browser_storage",'Panel "'+t.id+'" uses localStorage, sessionStorage or indexedDB. In CEP each panel gets its own copy and it can be cleared; save data with AP.storage instead. See docs/afterpresets/storage.md.'),c.licensed&&!c.rendersLicense&&i(n,"missing_render_license",'Panel "'+t.id+'" boots with licensing on but has no renderLicense. Pass renderLicense: function (api, root) { ... } to AP.boot. See docs/afterpresets/.'),c.licensed&&c.rendersLicense&&c.missingStatuses.forEach(a=>i(o,"license_status_unhandled",'Panel "'+t.id+'": license status "'+a+'" is not handled by its license screen code. See docs/afterpresets/.'))}E(d(e,b)).map(t=>N(e,t)).filter(t=>/\.(js|css|html)$/i.test(t)&&!f[t]).forEach(t=>i(o,"unused_file",t+" is not imported by any panel, so it is not built. Import it, or delete it."));const C=v(s.settings).map(t=>t.jsxDir).filter(Boolean),S={};F(e).forEach(t=>{const r=I(t);if(r&&C.indexOf(r)===-1){if(!S[r]){S[r]=!0;const h=R.find(p=>p.jsxDir===r).appName;i(o,"jsx_other_host",x+"/"+r+"/ is only loaded in "+h+", which this project does not target, so it is not built. Add the app with `ap add host "+r+"`, or move the files.")}return}/\.jsx$/i.test(t)||i(o,"jsx_not_loaded",t+" is not loaded: only .jsx files in "+x+"/ go into the build.")});const y={};s.panels.forEach(t=>y[t.id]=!0);const _=d(e,b+"/panels");return l.existsSync(_)&&l.readdirSync(_,{withFileTypes:!0}).filter(t=>t.isDirectory()&&!y[t.name]).forEach(t=>i(o,"unlisted_panel",b+"/panels/"+t.name+'/ is not listed in afterpresets.json, so it is not built. Add it to "panels" or delete the folder.')),{errors:n,warnings:o,panels:u,licensed:u.some(t=>t.licensed)}}function H(s,e){e.errors.forEach(o=>s.error(o.message)),e.warnings.forEach(o=>s.warn(o.message));const n=e.errors.length+" error(s), "+e.warnings.length+" warning(s)";e.errors.length?s.log(s.style.red("Check failed: "+n)):e.warnings.length?s.log(s.style.yellow("Check passed with "+n)):s.success("Check passed")}module.exports={checkProject:$,printCheck:H,stripComments:D,analyzePanelCode:P,LICENSE_STATUSES:j};
1
+ "use strict";const l=require("fs"),m=require("path"),{processIndexHtml:L}=require("../build/html"),{panelSources:q,SRC_DIR:b}=require("../build/build"),{bundlePanel:k,assetUrl:v}=require("../build/bundle"),{JSX_DIR:x,jsxDirFiles:T,hostDirOf:F}=require("../build/jsx"),{TARGETS:I,projectTargets:R}=require("../targets"),E=["signed_out","signing_in","checking","active","not_owned","refunded","offline_grace","offline_expired","error"],O=/\blicense\s*:\s*(?:true\b|\{)/,N=/\bAP\s*\.\s*boot\s*\(/;function j(s){if(!l.existsSync(s))return[];const e=[];return l.readdirSync(s,{withFileTypes:!0}).forEach(n=>{const o=m.join(s,n.name);n.isDirectory()?e.push.apply(e,j(o)):n.isFile()&&e.push(o)}),e}function P(s){let e="",n=0,o=null;for(;n<s.length;){const i=s[n],f=s[n+1];if(o){if(e+=i,i==="\\"){e+=f||"",n+=2;continue}i===o&&(o=null),n++;continue}if(i==='"'||i==="'"||i==="`"){o=i,e+=i,n++;continue}if(i==="/"&&f==="/"){for(;n<s.length&&s[n]!==`
2
+ `;)n++;continue}if(i==="/"&&f==="*"){const u=s.indexOf("*/",n+2);n=u===-1?s.length:u+2;continue}e+=i,n++}return e}function B(s,e){return m.relative(s,e).split(m.sep).join("/")}function d(s,e){return m.join(s,e.split("/").join(m.sep))}function D(s){const e=P(s),n=O.test(e);return{boots:N.test(e),licensed:n,rendersLicense:/\brenderLicense\b/.test(e),browserStorage:/\b(localStorage|sessionStorage|indexedDB)\b/.test(e),missingStatuses:E.filter(o=>!new RegExp("[\"'`]"+o+"[\"'`]").test(e))}}async function $(s){if(s.settings&&s.settings.platform==="native")return require("./native").checkNativeProject(s);const e=s.root,n=[],o=[],i=(t,r,h)=>t.push({code:r,message:h}),f={},u=[];for(const t of s.panels){const r=q(t.id);f[r.html]=!0;const h={id:t.id,boots:!1,licensed:!1};if(u.push(h),!l.existsSync(d(e,r.dir))){i(n,"missing_panel",'afterpresets.json lists panel "'+t.id+'" but '+r.dir+"/ does not exist. Run `ap add panel "+t.id+"` or remove it from afterpresets.json.");continue}if([r.html,r.js].forEach(a=>{l.existsSync(d(e,a))||i(n,"missing_entry","Missing "+a+".")}),l.existsSync(d(e,r.html))){const a=d(e,r.html),w=L(l.readFileSync(a,"utf8"),r.html,r.js,g=>v(e,s.settings,a,g));w.errors.forEach(g=>i(n,"index_html",g)),w.warnings.forEach(g=>i(o,"index_html",g))}if(!l.existsSync(d(e,r.js)))continue;let p;try{p=await k(e,r.js,s.settings)}catch(a){i(n,"bundle_failed",a.message);continue}p.inputs.forEach(a=>f[a]=!0);const A=p.inputs.filter(a=>/\.(js|html)$/i.test(a)&&!/(^|\/)node_modules\//.test(a)).map(a=>l.readFileSync(d(e,a),"utf8")).join(`
3
+ `),c=D(A);h.boots=c.boots,h.licensed=c.licensed,c.boots||i(n,"missing_boot",'Panel "'+t.id+'" never calls AP.boot(...). Start the panel from AP.boot({ start: ... }) in '+r.js+"."),c.browserStorage&&i(o,"browser_storage",'Panel "'+t.id+'" uses localStorage, sessionStorage or indexedDB. In CEP each panel gets its own copy and it can be cleared; save data with AP.storage instead. See docs/afterpresets/storage.md.'),c.licensed&&!c.rendersLicense&&i(n,"missing_render_license",'Panel "'+t.id+'" boots with licensing on but has no renderLicense. Pass renderLicense: function (api, root) { ... } to AP.boot. See docs/afterpresets/.'),c.licensed&&c.rendersLicense&&c.missingStatuses.forEach(a=>i(o,"license_status_unhandled",'Panel "'+t.id+'": license status "'+a+'" is not handled by its license screen code. See docs/afterpresets/.'))}j(d(e,b)).map(t=>B(e,t)).filter(t=>/\.(js|css|html)$/i.test(t)&&!f[t]).forEach(t=>i(o,"unused_file",t+" is not imported by any panel, so it is not built. Import it, or delete it."));const C=R(s.settings).map(t=>t.jsxDir).filter(Boolean),S={};T(e).forEach(t=>{const r=F(t);if(r&&C.indexOf(r)===-1){if(!S[r]){S[r]=!0;const h=I.find(p=>p.jsxDir===r).appName;i(o,"jsx_other_host",x+"/"+r+"/ is only loaded in "+h+", which this project does not target, so it is not built. Add the app with `ap add host "+r+"`, or move the files.")}return}/\.jsx$/i.test(t)||i(o,"jsx_not_loaded",t+" is not loaded: only .jsx files in "+x+"/ go into the build.")});const y={};s.panels.forEach(t=>y[t.id]=!0);const _=d(e,b+"/panels");return l.existsSync(_)&&l.readdirSync(_,{withFileTypes:!0}).filter(t=>t.isDirectory()&&!y[t.name]).forEach(t=>i(o,"unlisted_panel",b+"/panels/"+t.name+'/ is not listed in afterpresets.json, so it is not built. Add it to "panels" or delete the folder.')),{errors:n,warnings:o,panels:u,licensed:u.some(t=>t.licensed)}}function H(s,e){e.errors.forEach(o=>s.error(o.message)),e.warnings.forEach(o=>s.warn(o.message));const n=e.errors.length+" error(s), "+e.warnings.length+" warning(s)";e.errors.length?s.log(s.style.red("Check failed: "+n)):e.warnings.length?s.log(s.style.yellow("Check passed with "+n)):s.success("Check passed")}module.exports={checkProject:$,printCheck:H,stripComments:P,analyzePanelCode:D,LICENSE_STATUSES:E};
@@ -0,0 +1,14 @@
1
+ "use strict";const U=require("crypto"),L=require("fs"),R=require("path"),H=/\.(c|cc|cpp|cxx|h|hh|hpp|hxx|m|mm|inl)$/i,B=/\.(c|cc|cpp|cxx|h|hh|hpp|hxx|m|mm|inl|r|rc|txt|md|json|cmake|plist|js|jsx|py|sh|bat|command)$/i,K=["build","dist","dist-dev","node_modules",".git","vendor","out"],X=["docs/afterpresets"],$=2*1024*1024,I={slider:"fs_d",angle:"ad",color:"cd",point:"td",checkbox:"bd",popup:"pd"},W=["sd","fs_d","ad","cd","td","bd","pd","ld","path_d","arb_d","button_d"],j=["A.h","AE_Effect.h","AE_EffectCB.h","AE_EffectCBSuites.h","AE_EffectSuites.h","AE_EffectSuitesHelper.h","AE_EffectUI.h","AE_EffectPixelFormat.h","AE_EffectGPUSuites.h","AE_EffectVers.h","AE_GeneralPlug.h","AE_GeneralPlugOld.h","AE_GeneralPlugPanels.h","AE_Hook.h","AE_IO.h","AE_IO_FileExt.h","AE_Macros.h","AE_PluginData.h","AEConfig.h","AEFX_ArbParseHelper.h","AEFX_ChannelDepthTpl.h","AEFX_SuiteHelper.h","AEGP_SuiteHandler.h","AEGP_SuiteHandler.cpp","AEGP_Utils.h","AE_ChannelSuites.h","AE_AdvEffectSuites.h","AE_ComputeCacheSuite.h","DrawbotSuite.h","FIEL_Public.h","Param_Utils.h","PF_Masks.h","PR_Public.h","PT_Public.h","SPAccess.h","SPAdapts.h","SPBasic.h","SPBckDbg.h","SPCaches.h","SPConfig.h","SPErrorCodes.h","SPErrors.h","SPFiles.h","SPHost.h","SPInterf.h","SPMData.h","SPPiPL.h","SPPlugs.h","SPProps.h","SPSuites.h","SPTypes.h","Smart_Utils.h","Smart_Utils.cpp","String_Utils.h","entry.h","AE_Effect.r","AE_General.r","AE_PluginData.r","AE_SDK.xcconfig","PiPLtool.exe","PiPLTool.exe"],Z=[/ADOBE\s+CONFIDENTIAL/,/Copyright\s*(?:\(c\)|©)?\s*(?:19|20)\d\d(?:\s*[-,]\s*(?:19|20)\d\d)?[^\n]{0,20}Adobe/i,/Adobe\s+Systems\s+Incorporated/i,/Adobe\s+permits\s+you\s+to\s+use,\s+modify,\s+and\s+distribute/i],q=["3521eb14b4afc632c9fa9e77093bfc501832c04adaf864c46e1bd8776f87f77e","0461c1fe4a979d33a1d8bda78c548d2af04b38e7ac772d405fe1efea3010d38f"],z=[{re:/\b(?:usleep|nanosleep|sleep|Sleep|SleepEx)\s*\(/,what:"sleeps"},{re:/\bsleep_for\s*\(|\bsleep_until\s*\(/,what:"sleeps"},{re:/\b(?:socket|getaddrinfo|gethostbyname|WSAStartup|recv|send)\s*\(/,what:"uses the network"},{re:/\bcurl_\w+\s*\(|\bWinHttp\w*\s*\(|\bInternetOpen\w*\s*\(|\bNSURLSession\b|\bNSURLConnection\b|\bCFNetwork\b|\bURLSession\b/,what:"uses the network"},{re:/\b(?:system|popen|_popen|fork|execv|execvp|CreateProcess\w*|ShellExecute\w*)\s*\(/,what:"starts a process"},{re:/\bMessageBox\w*\s*\(|\bNSAlert\b|\bstd::cin\b|\bgetchar\s*\(/,what:"waits for the user"}];function N(t,o,e){let i;try{i=L.readdirSync(o,{withFileTypes:!0})}catch{return e}return i.forEach(n=>{const r=R.join(o,n.name),c=R.relative(t,r).split(R.sep).join("/");if(n.isDirectory()){if(K.indexOf(n.name)!==-1||X.indexOf(c)!==-1||/\.(plugin|bundle)$/i.test(n.name))return;N(t,r,e)}else n.isFile()&&e.push(c)}),e}function v(t,o){const e=R.join(t,o.split("/").join(R.sep));try{return L.statSync(e).size>$?null:L.readFileSync(e,"utf8")}catch{return null}}function M(t){let o="",e=0;const i=t.length;let n=!0;for(;e<i;){const r=t[e],c=t[e+1];if(n&&r==="#"){for(;e<i&&t[e]!==`
2
+ `;){if(t[e]==="\\"&&t[e+1]===`
3
+ `){o+=`
4
+ `,e+=2;continue}o+=" ",e++}continue}if(r==="/"&&c==="/"){for(;e<i&&t[e]!==`
5
+ `;)o+=" ",e++;continue}if(r==="/"&&c==="*"){for(o+=" ",e+=2;e<i&&!(t[e]==="*"&&t[e+1]==="/");)o+=t[e]===`
6
+ `?`
7
+ `:" ",e++;e<i&&(o+=" ",e+=2);continue}if(r==='"'||r==="'"){for(o+=r,e++;e<i&&t[e]!==r&&t[e]!==`
8
+ `;)t[e]==="\\"&&(o+=" ",e++),o+=e<i?t[e]===`
9
+ `?`
10
+ `:" ":"",e++;e<i&&t[e]===r&&(o+=r,e++);continue}r===`
11
+ `?n=!0:r!==" "&&r!==" "&&r!=="\r"&&(n=!1),o+=r,e++}return o}function F(t,o){let e=1;for(let i=0;i<o&&i<t.length;i++)t.charCodeAt(i)===10&&e++;return e}function V(t){const o={};return t.split(`
12
+ `).forEach((e,i)=>{const n=e.match(/ap-check:\s*allow\b([^\n]*)/);n&&(o[i+1]=n[1])}),o}function T(t,o,e){return[o,o-1].some(i=>{const n=t[i];return n!==void 0&&(!n.trim()||n.indexOf(e)!==-1)})}const Y=/^(?:const|constexpr|consteval|constinit|typedef|using|extern|template|return|namespace|class|struct|union|enum|friend|case|default|goto|public|private|protected|static_assert|thread_local|delete|throw|break|continue|operator|virtual|explicit|inline\s+constexpr)\b/,J=/\b(?:std::)?(?:atomic\w*|mutex|shared_mutex|recursive_mutex|once_flag|condition_variable)\b|\bthread_local\b|\bconst\b|\bconstexpr\b/;function G(t){const o=[],e=[];let i=-1,n="",r=0;const c=()=>e.filter(a=>a==="block").length;function A(a,m){const _=n.replace(/\s+/g," ").trim(),P=i;if(n="",i=-1,!_)return;const p=c(),E=/^(?:\[\[[^\]]*\]\]\s*)?static\b/.test(_);if(p>0&&!E)return;const s=_.replace(/^(?:\[\[[^\]]*\]\]\s*)?static\s+/,"").replace(/^inline\s+/,"");if(Y.test(s)||J.test(_)||a==="{")return;const h=s.indexOf("{"),d=s.indexOf("="),f=h!==-1&&(d===-1||h<d)?h:d,l=s.indexOf("(");if(l!==-1&&(f===-1||l<f))return;const u=f===-1?s:s.slice(0,f);/^[A-Za-z_][\w:<>,\s*&]*[\s*&]\**\s*[A-Za-z_]\w*\s*(\[[^\]]*\]\s*)*$/.test(u.trim())&&o.push({line:F(t,P),text:_.length>80?_.slice(0,77)+"...":_})}for(let a=0;a<t.length;a++){const m=t[a];if(m==="("&&r++,m===")"&&(r=Math.max(0,r-1)),r>0){n+=m;continue}if(m===";"){A(";",a);continue}if(m==="{"){const _=n.replace(/\s+/g," ").trim();if(/=\s*$/.test(_)||/^(?:static\s+)?[A-Za-z_][\w:<>,\s*&]*\s[A-Za-z_]\w*\s*$/.test(_)&&!/^(?:namespace|class|struct|union|enum|extern)\b/.test(_)&&c()===0&&!/\)\s*(?:const)?\s*$/.test(_)){let p=1;n+="{";let E=a+1;for(;E<t.length&&p>0;E++)t[E]==="{"?p++:t[E]==="}"&&p--,n+=t[E];a=E-1;continue}const P=/^(?:inline\s+)?namespace\b/.test(_)||/^extern\s*""\s*$/.test(_)||/^extern\s*"C"\s*$/.test(_);A("{",a),e.push(P?"ns":"block");continue}if(m==="}"){A("}",a),e.pop();continue}i===-1&&!/\s/.test(m)&&(i=a),n+=m}return o}function Q(t){return String(t).toUpperCase()}function ee(t,o){const e=o||{},i=t.root,n=[],r=[],c=(s,h,d,f,l)=>s.push({code:h,file:d||null,line:f||null,message:(d?d+(f?":"+f:"")+": ":"")+l}),A=e.effectLib||te("../native/effect");let a=null;if(!A)c(r,"effect_json","effect.json",null,"This CLI cannot validate effect.json (no native toolchain). Run `ap upgrade`.");else try{a=A.loadEffect(i)}catch(s){(s&&Array.isArray(s.problems)?s.problems:[s.message]).forEach(d=>c(n,"effect_json","effect.json",null,d))}const m=t.settings.releasedEffect;a&&m&&A&&typeof A.compatibilityProblems=="function"&&A.compatibilityProblems({matchName:m.matchName,params:m.params||[]},a).forEach(s=>c(n,"effect_changed","effect.json",null,s+" (Version "+(m.version||"?")+" was released with the old value.)"));const _=N(i,i,[]),P=_.filter(s=>/^src\//.test(s)&&H.test(s)),p={};P.forEach(s=>{const h=v(i,s);h!==null&&(p[s]={raw:h,code:M(h),allow:V(h)})});const E=Object.keys(p).map(s=>p[s].code).join(`
13
+ `);if(P.length&&!/\bEffectMain\b/.test(E)&&c(n,"missing_entry_point","src/",null,"No EffectMain function. After Effects calls the entry point named in the PiPL (EffectMain); keep the starter's `PF_Err EffectMain(...)` with its export macro."),a){const s=a.outFlags||[],h=a.outFlags2||[];Object.keys(p).forEach(f=>{const l=p[f],u=/\bout_flags(2?)\s*(\|?=)\s*([^;]+);/g;let b;for(;b=u.exec(l.code);){const g=b[1]?"AP_OUT_FLAGS2":"AP_OUT_FLAGS",D=F(l.code,b.index);if(T(l.allow,D,"out_flags"))continue;const y=b[1]?A.OUT_FLAGS2||{}:A.OUT_FLAGS||{},S=(b[3].match(/PF_OutFlag2?_(\w+)/g)||[]).map(x=>x.replace(/^PF_OutFlag2?_/,"")).filter(x=>Object.prototype.hasOwnProperty.call(y,x));(b[2]==="|="?S.length>0:!/\bAP_OUT_FLAGS2?\b/.test(b[3])||S.length>0)&&c(n,"out_flags",f,D,"Set out_data->out_flags"+b[1]+" = "+g+'; exactly (generated from effect.json). The PiPL carries the same flags and After Effects refuses an effect whose flags disagree. Change flags in effect.json "outFlags'+b[1]+'".')}}),h.indexOf("SUPPORTS_SMART_RENDER")!==-1&&P.length&&!/\bPF_Cmd_SMART_RENDER\b/.test(E)&&c(n,"smart_render","src/",null,"effect.json promises Smart Render (SUPPORTS_SMART_RENDER) but no code handles PF_Cmd_SMART_PRE_RENDER / PF_Cmd_SMART_RENDER. Handle both (see the starter), or remove the flag."),s.indexOf("DEEP_COLOR_AWARE")!==-1&&P.length&&!/\bPF_Pixel16\b|\bPF_PixelFormat_ARGB64\b|\biterate16\b|\bPF_WORLD_IS_DEEP\b/.test(E)&&c(r,"bit_depth","src/",null,"effect.json says 16 bpc (DEEP_COLOR_AWARE) but no code handles PF_Pixel16 / PF_PixelFormat_ARGB64. Render 16-bpc worlds too, or remove the flag."),h.indexOf("FLOAT_COLOR_AWARE")!==-1&&P.length&&!/\bPF_PixelFloat\b|\bPF_PixelFormat_ARGB128\b|\bPF_Pixel32\b/.test(E)&&c(r,"bit_depth","src/",null,"effect.json says 32 bpc (FLOAT_COLOR_AWARE) but no code handles PF_PixelFloat / PF_PixelFormat_ARGB128. Render float worlds too, or remove the flag."),s.indexOf("I_DO_DIALOG")!==-1&&P.length&&!/\bPF_Cmd_DO_DIALOG\b/.test(E)&&c(r,"dialog","src/",null,"effect.json sets I_DO_DIALOG (the Options button) but no code handles PF_Cmd_DO_DIALOG."),h.indexOf("SUPPORTS_THREADED_RENDERING")!==-1&&Object.keys(p).forEach(f=>{const l=p[f];G(l.code).forEach(u=>{T(l.allow,u.line,"mfr_global")||c(n,"mfr_global",f,u.line,"`"+u.text+"` is a mutable global/static, but multi-frame rendering (SUPPORTS_THREADED_RENDERING) renders several frames at once on different threads. Make it const, keep the value in a local variable or the effect's sequence data, or use std::atomic / a mutex. If it is written only in GLOBAL_SETUP/GLOBAL_SETDOWN (before or after every render) or is already thread-safe, put `// ap-check: allow mfr_global` on that line or the line above.")})});const d={};a.params.forEach(f=>d["AP_PARAM_"+Q(f.key)]=f),Object.keys(p).forEach(f=>{const l=p[f],u=(w,S,O)=>{const x=d[w],k=x&&I[x.type];if(!k||S===k||W.indexOf(S)===-1)return;const C=F(l.code,O);T(l.allow,C,"param_union")||c(n,"param_union",f,C,w+" is a "+x.type+' ("'+x.name+'"): read it with u.'+k+" (not u."+S+"); the other members hold garbage for this type.")},b=/\[\s*(AP_PARAM_[A-Z0-9_]+)\s*\]\s*(?:->|\.)\s*u\s*\.\s*(\w+)/g;let g;for(;g=b.exec(l.code);)u(g[1],g[2],g.index);const D=/PF_CHECKOUT_PARAM\s*\(\s*[^,]+,\s*(AP_PARAM_[A-Z0-9_]+)\s*,[^;]*?&\s*([A-Za-z_]\w*)\s*\)/g,y={};for(;g=D.exec(l.code);)y[g[2]]=g[1];Object.keys(y).forEach(w=>{const S=new RegExp("\\b"+w+"\\s*(?:->|\\.)\\s*u\\s*\\.\\s*(\\w+)","g");let O;for(;O=S.exec(l.code);)u(y[w],O[1],O.index)})})}return Object.keys(p).forEach(s=>{const h=p[s],d=/\b65535(?:\.0*)?[fFuU]?\b|\b0[xX][fF]{4}\b/g;let f;for(;f=d.exec(h.code);){const l=F(h.code,f.index);T(h.allow,l,"chan16_max")||c(n,"chan16_max",s,l,"After Effects' 16-bpc white is 32768 (PF_MAX_CHAN16), not 65535. Use PF_MAX_CHAN16, or add `// ap-check: allow chan16_max` if this is not a pixel value.")}h.code.split(`
14
+ `).forEach((l,u)=>{z.forEach(b=>{!b.re.test(l)||T(h.allow,u+1,"blocking_call")||c(n,"blocking_call",s,u+1,"This "+b.what+". After Effects calls Render on many threads at once and waits for it, so it must never wait or do I/O; ap_native already checks licences and updates on its own thread. Move it out of the render path, or add `// ap-check: allow blocking_call` for code that never runs while rendering.")})})}),_.forEach(s=>{const h=R.posix.basename(s);if(j.indexOf(h)!==-1){c(n,"sdk_file",s,null,"This is a file from Adobe's After Effects SDK. Delete it: the build reads the SDK from `ap sdk`'s folder on this computer, and Adobe's files must not be copied into your project or shipped.");return}if(/\.r$/i.test(s)&&/^src\//.test(s)){const u=v(i,s);u&&/\bPiPL\b/.test(u)&&c(r,"pipl_file",s,null,"The build generates the PiPL from effect.json; this hand-written PiPL is not used. Delete it and change effect.json instead.")}if(!B.test(s))return;const d=v(i,s);if(d===null)return;for(const u of Z){const b=u.exec(d);if(b){c(n,"sdk_file",s,F(d,b.index),"This file contains Adobe's SDK copyright text, so it looks copied from the SDK. Write your own code (the SDK guide in docs/afterpresets/sdk/ explains the APIs) and delete the copied text.");break}}const l=(d.match(/\bsave[A-Za-z]{4,20}\b/g)||[]).find(u=>q.indexOf(U.createHash("sha256").update(u).digest("hex"))!==-1);l&&c(n,"private_api",s,F(d,d.indexOf(l)),"`"+l+"` is not part of After Effects' public scripting API. Remove it from the project; use the documented API (to look at frames while developing, use comp_capture).")}),a&&a.license&&a.license.enabled&&P.length&&!/\bap_is_unlocked\s*\(/.test(E)&&c(r,"license_unused","src/",null,"Licensing is on in effect.json but no code calls ap_is_unlocked(). Render must check it (the starter draws a watermark when it returns 0), or buyers without a licence get the full effect."),{errors:n,warnings:r,panels:[],licensed:!!(a&&a.license&&a.license.enabled),native:!0,effect:a}}function te(t){try{return require(t)}catch{return null}}function se(t,o){return{version:o,matchName:t.matchName,params:t.params.map(e=>({id:e.id,type:e.type,name:e.name}))}}module.exports={checkNativeProject:ee,releasedEffectRecord:se,stripCode:M,mutableGlobals:G,SDK_FILE_NAMES:j,UNION_MEMBER:I};
@@ -1 +1 @@
1
- "use strict";const{readCredentials:d}=require("../auth/credentials"),{createApiClient:a}=require("../api/client"),{productPath:l}=require("../api/session");function c(r,t){const e=(r/100).toFixed(2);return t?e+" "+String(t).toUpperCase():e}function u(r,t){const e=[],n=[],s=r?r.priceMinor:void 0;if(s===void 0)return n.push({code:"price_unknown",message:"The API did not report this product's price, so the paid-product licensing rule could not be verified."}),{errors:e,warnings:n};if(!(Number(s)>0))return{errors:e,warnings:n};const o=c(Number(s),r.currency);return t.licensed?(t.panels.filter(i=>i.boots&&!i.licensed).forEach(i=>n.push({code:"paid_panel_unlicensed",message:'Panel "'+i.id+'" boots without licensing although the product is paid. Make sure it does nothing useful without a license.'})),{errors:e,warnings:n}):(e.push({code:"paid_without_license",message:"This product is paid ("+o+") but no panel boots with licensing on. Pass `license: true` and a renderLicense function to AP.boot in src/panels/<id>/main.js. See docs/afterpresets/."}),{errors:e,warnings:n})}async function p(r,t,e){const n=d(r),s=i=>({errors:[],warnings:[{code:"price_unverified",message:"Could not verify the product price ("+i+"). Paid products must boot with licensing on; `ap push` enforces this."}],verified:!1});if(!n)return s("not logged in");let o;try{o=await a(r,n).get(l(t.settings.bundleId))}catch(i){return s(i.code==="network_error"?"offline":i.code||i.message)}return Object.assign(u(o.product||null,e),{verified:!0})}module.exports={pricingProblems:u,verifyPricingOnline:p,formatPrice:c};
1
+ "use strict";const{readCredentials:u}=require("../auth/credentials"),{createApiClient:a}=require("../api/client"),{productPath:l}=require("../api/session");function c(r,t){const e=(r/100).toFixed(2);return t?e+" "+String(t).toUpperCase():e}function d(r,t){const e=[],i=[],s=r?r.priceMinor:void 0;if(s===void 0)return i.push({code:"price_unknown",message:"The API did not report this product's price, so the paid-product licensing rule could not be verified."}),{errors:e,warnings:i};if(!(Number(s)>0))return{errors:e,warnings:i};const o=c(Number(s),r.currency);return!t.licensed&&t.native?(e.push({code:"paid_without_license",message:"This product is paid ("+o+') but effect.json turns licensing off ("license": false). Remove that line (licensing is on by default). See docs/afterpresets/.'}),{errors:e,warnings:i}):t.licensed?(t.panels.filter(n=>n.boots&&!n.licensed).forEach(n=>i.push({code:"paid_panel_unlicensed",message:'Panel "'+n.id+'" boots without licensing although the product is paid. Make sure it does nothing useful without a license.'})),{errors:e,warnings:i}):(e.push({code:"paid_without_license",message:"This product is paid ("+o+") but no panel boots with licensing on. Pass `license: true` and a renderLicense function to AP.boot in src/panels/<id>/main.js. See docs/afterpresets/."}),{errors:e,warnings:i})}async function p(r,t,e){const i=u(r),s=n=>({errors:[],warnings:[{code:"price_unverified",message:"Could not verify the product price ("+n+"). Paid products must boot with licensing on; `ap push` enforces this."}],verified:!1});if(!i)return s("not logged in");let o;try{o=await a(r,i).get(l(t.settings.bundleId))}catch(n){return s(n.code==="network_error"?"offline":n.code||n.message)}return Object.assign(d(o.product||null,e),{verified:!0})}module.exports={pricingProblems:d,verifyPricingOnline:p,formatPrice:c};
package/src/cli.js CHANGED
@@ -1,5 +1,5 @@
1
- "use strict";const{parseArgs:c}=require("./args"),{CliError:g}=require("./errors"),{findProjectRoot:m}=require("./project/project"),i=["login","logout","whoami","init","dev","check","add","build","push","releases","testers","docs","upgrade","config","mcp"].map(e=>require("./commands/"+e)),s=require("../package.json").version,l=require("./system/update-check");async function h(e,r){if(!(r==="mcp"||r==="upgrade"||!(e.stdout&&e.stdout.isTTY)))try{const o=await l.newerVersion(e);o&&e.out.log(`
2
- `+e.out.style.dim(l.noticeText(o)))}catch{}}function a(e){return i.find(r=>r.name===e)||null}function f(e){e.banner("CLI "+s+" \xB7 build and publish After Effects and Premiere Pro extensions"),e.log("Usage: "+e.style.cyan("ap <command>")+` [options]
1
+ "use strict";const{parseArgs:g}=require("./args"),{CliError:c}=require("./errors"),{findProjectRoot:h}=require("./project/project"),i=["login","logout","whoami","init","dev","panel","host","comp","check","add","build","push","releases","testers","docs","sdk","upgrade","config"].map(e=>require("./commands/"+e)),s=require("../package.json").version,l=require("./system/update-check");async function m(e,r){if(!(r==="upgrade"||!(e.stdout&&e.stdout.isTTY)))try{const o=await l.newerVersion(e);o&&e.out.log(`
2
+ `+e.out.style.dim(l.noticeText(o)))}catch{}}function a(e){return i.find(r=>r.name===e)||null}function f(e){e.banner("CLI "+s+" \xB7 build and publish After Effects and Premiere Pro extensions and effect plugins"),e.log("Usage: "+e.style.cyan("ap <command>")+` [options]
3
3
  `),i.forEach(r=>e.log(" "+e.style.cyan(r.name.padEnd(10))+r.summary)),e.log(`
4
4
  `+e.style.dim("Run `ap <command> --help` for details. Agent reference: docs/afterpresets/ in your project."))}function d(e,r){e.log("Usage: "+r.usage+`
5
- `),e.log(r.description)}async function y(e,r){const o=e[0];if(!o&&r.prompt&&!m(r.cwd))return p(r,a("init"),[],n=>require("./commands/init").wizard(n));if(!o||o==="help"||o==="--help"||o==="-h"){const n=o==="help"&&e[1]?a(e[1]):null;return n?d(r.out,n):f(r.out),0}if(o==="--version"||o==="-v")return r.out.log(s),0;const t=a(o);return t?p(r,t,e.slice(1)):(r.out.error("Unknown command: "+o),f(r.out),2)}async function p(e,r,o,t){try{let n;if(t)n=await t(e);else{const u=c(o,r.flags);if(u.flags.help)return d(e.out,r),0;n=await r.run(e,u)}return await h(e,r.name),typeof n=="number"?n:0}catch(n){return n instanceof g?(e.out.error(n.message),n.hint&&e.out.log(" "+n.hint),n.exitCode===2&&e.out.log(" Usage: "+r.usage),n.exitCode||1):(e.out.error("Unexpected error: "+(n&&n.message?n.message:String(n))),e.env.AP_DEBUG?e.out.log(n&&n.stack):e.out.log(" Set AP_DEBUG=1 for the stack trace."),1)}}module.exports={main:y,COMMANDS:i,VERSION:s};
5
+ `),e.log(r.description)}async function y(e,r){const o=e[0];if(!o&&r.prompt&&!h(r.cwd))return p(r,a("init"),[],n=>require("./commands/init").wizard(n));if(!o||o==="help"||o==="--help"||o==="-h"){const n=o==="help"&&e[1]?a(e[1]):null;return n?d(r.out,n):f(r.out),0}if(o==="--version"||o==="-v")return r.out.log(s),0;const t=a(o);return t?p(r,t,e.slice(1)):(r.out.error("Unknown command: "+o),f(r.out),2)}async function p(e,r,o,t){try{let n;if(t)n=await t(e);else if(r.raw)n=await r.run(e,o);else{const u=g(o,r.flags);if(u.flags.help)return d(e.out,r),0;n=await r.run(e,u)}return await m(e,r.name),typeof n=="number"?n:0}catch(n){return n instanceof c?(e.out.error(n.message),n.hint&&e.out.log(" "+n.hint),n.exitCode===2&&!r.raw&&e.out.log(" Usage: "+r.usage),n.exitCode||1):(e.out.error("Unexpected error: "+(n&&n.message?n.message:String(n))),e.env.AP_DEBUG?e.out.log(n&&n.stack):e.out.log(" Set AP_DEBUG=1 for the stack trace."),1)}}module.exports={main:y,COMMANDS:i,VERSION:s};
@@ -1,6 +1,12 @@
1
- "use strict";const l=require("path"),o=require("../config"),{readCredentials:c}=require("../auth/credentials"),{loadProject:p}=require("../project/project"),{checkProject:h,printCheck:g}=require("../check/check"),{pricingProblems:f}=require("../check/pricing"),{buildProject:m,productionOutDir:w}=require("../build/build"),{CliError:b}=require("../errors");async function u(e,n,r){const i=await h(n);if(r!==void 0){const t=f(r,i);i.errors.push.apply(i.errors,t.errors),i.warnings.push.apply(i.warnings,t.warnings)}if((i.errors.length||i.warnings.length)&&g(e.out,i),i.errors.length)throw new b("Fix the check errors above before building.");return i}async function a(e,n,r,i){i&&i.checked||await u(e,n);const t=o.apiBase(e,c(e));t!==o.DEFAULT_API_BASE&&e.out.warn("This build talks to "+t+" (AP_API_BASE, `ap config`, or your login), not production.");const s=await m(e,n,{outDir:w(n),dev:!1,version:r,apiBase:t,compileJsx:e.compileJsx});return s.warnings.forEach(d=>e.out.warn(d)),s}module.exports={name:"build",summary:"Build the production bundle into dist/<bundleId>/",usage:"ap build",description:`Runs the check, then for every panel in afterpresets.json writes one main.js with
1
+ "use strict";const u=require("path"),c=require("../config"),{readCredentials:b}=require("../auth/credentials"),{loadProject:w}=require("../project/project"),{checkProject:v,printCheck:y}=require("../check/check"),{pricingProblems:k}=require("../check/pricing"),{buildProject:B,productionOutDir:I}=require("../build/build"),{CliError:h}=require("../errors");async function f(e,i,t){const n=await v(i);if(t!==void 0){const s=k(t,n);n.errors.push.apply(n.errors,s.errors),n.warnings.push.apply(n.warnings,s.warnings)}if((n.errors.length||n.warnings.length)&&y(e.out,n),n.errors.length)throw new h("Fix the check errors above before building.");return n}async function g(e,i,t,n){n&&n.checked||await f(e,i);const s=c.apiBase(e,b(e));s!==c.DEFAULT_API_BASE&&e.out.warn("This build talks to "+s+" (AP_API_BASE, `ap config`, or your login), not production.");const a=await B(e,i,{outDir:I(i),dev:!1,version:t,apiBase:s,compileJsx:e.compileJsx});return a.warnings.forEach(r=>e.out.warn(r)),a}async function m(e,i,t){const n=require("fs"),s=require("../release/native"),a=s.resolveReleaseOses(e,t&&t.os),r=await e.out.task("Building "+i.settings.name+" for "+s.osesLabel(a),()=>s.buildNativeRelease(e,i,i.version,Object.assign({},t,{os:a})),o=>"Built "+i.settings.bundleId+" "+o.version+e.out.style.dim(" (ap_native "+o.runtimeVersion+")"));r.warnings.forEach(o=>e.out.warn(o));const l=s.assembleNativeZip(e,r.artefacts,{bundleId:i.settings.bundleId,name:i.settings.name,version:r.version,listingUrl:i.settings.listingUrl||null}),d=s.nativeZipPath(i,r.version);n.mkdirSync(u.dirname(d),{recursive:!0}),n.writeFileSync(d,l.buffer);const p=l.entries.filter(o=>!/\.plugin\//.test(o)).concat(r.artefacts.mac?[u.basename(r.artefacts.mac)+"/"]:[]);return e.out.success("Wrote "+u.relative(e.cwd,d)+s.publishedOsSuffix(null,r.oses)+e.out.style.dim(" ("+Math.max(1,Math.round(l.sizeBytes/1024))+" KB: "+p.join(", ")+")")),0}module.exports={name:"build",summary:"Build the production bundle into dist/<bundleId>/",usage:"ap build [--os mac,win]",description:`Runs the check, then for every panel in afterpresets.json writes one main.js with
2
2
  the JSXBIN-compiled jsx/ folder, the panel's imported CSS, its index.html <body>,
3
3
  the runtime and src/panels/<id>/main.js with its imports, plus a thin index.html;
4
4
  generates CSXS/manifest.xml, and
5
5
  copies the asset folders. Needs a signing public key (AP_SIGNING_PUBLIC_KEY or
6
- \`ap config set signing-public-key\`) until the production key is embedded.`,flags:{},checkedProductionBuild:a,runGate:u,async run(e){const n=p(e);return await e.out.task("Building "+n.settings.bundleId,()=>a(e,n),r=>"Built "+n.settings.bundleId+" "+r.version+e.out.style.dim(" (runtime "+r.runtimeVersion+") into "+l.relative(e.cwd,r.outDir))),0}};
6
+ \`ap config set signing-public-key\`) until the production key is embedded.
7
+
8
+ Native effect plugins: runs the check, builds the release plugin for macOS
9
+ (universal, ad-hoc signed) and Windows (.aex), and writes the buyer ZIP with its
10
+ install scripts to dist/<bundleId>-<version>.zip, exactly what \`ap push\` uploads.
11
+ A Mac builds both; Windows builds the Windows version only (build the macOS
12
+ version on a Mac). --os mac, --os win or --os mac,win picks the versions.`,flags:{os:{type:"string"}},checkedProductionBuild:g,buildNativeZip:m,runGate:f,async run(e,i){const t=w(e),n=i&&i.flags?i.flags.os:void 0;if(t.settings.platform==="native")return m(e,t,{os:n});if(n!==void 0)throw new h("--os is for native effect plugins; CEP extensions run on both macOS and Windows.");return await e.out.task("Building "+t.settings.bundleId,()=>g(e,t),s=>"Built "+t.settings.bundleId+" "+s.version+e.out.style.dim(" (runtime "+s.runtimeVersion+") into "+u.relative(e.cwd,s.outDir))),0}};
@@ -1,4 +1,4 @@
1
- "use strict";const{loadProject:l}=require("../project/project"),{checkProject:p,printCheck:c}=require("../check/check"),{verifyPricingOnline:h}=require("../check/pricing"),{typeHints:u,hintLines:d,typesLabel:g}=require("../check/types");module.exports={name:"check",summary:"Run the static checks that gate a push",usage:"ap check [--types] [--types-all]",description:`Errors: a panel folder lacks index.html or main.js; a panel's code does not bundle
1
+ "use strict";const{loadProject:l}=require("../project/project"),{checkProject:c,printCheck:p}=require("../check/check"),{verifyPricingOnline:h}=require("../check/pricing"),{typeHints:d,hintLines:u,typesLabel:g}=require("../check/types");module.exports={name:"check",summary:"Run the static checks that gate a push",usage:"ap check [--types] [--types-all]",description:`Errors: a panel folder lacks index.html or main.js; a panel's code does not bundle
2
2
  (a missing import, or syntax newer than ES5); a panel never calls AP.boot(; a panel
3
3
  turns licensing on without a renderLicense; a panel's index.html does not load
4
4
  main.js; or the product is paid and no panel boots with licensing on.
@@ -10,4 +10,12 @@ The paid-product rule needs \`ap login\`; offline it is a warning (ap push enfor
10
10
  app's API types (After Effects, Premiere Pro) and lists likely mistakes (misspelled names and
11
11
  properties, wrong argument counts, methods ES3 lacks such as "".trim()).
12
12
  Hints can be wrong (the types have gaps) and never fail the check.
13
- --types-all Also lists every other hint. Expect false alarms on working code.`,flags:{types:{type:"boolean"},"types-all":{type:"boolean"}},async run(n,t){const s=l(n),e=await p(s),a=await h(n,s,e);e.errors.push.apply(e.errors,a.errors),e.warnings.push.apply(e.warnings,a.warnings),c(n.out,e);const r=!!t.flags["types-all"];return(r||t.flags.types)&&(n.out.log(""),d(u(s),r,g(s)).forEach((o,i)=>n.out.log(i===1?n.out.style.dim(o):o))),e.errors.length?1:0}};
13
+ --types-all Also lists every other hint. Expect false alarms on working code.
14
+
15
+ Native effect plugins: effect.json is valid; matchName and param ids/types unchanged
16
+ since the last release; an EffectMain entry point; out_flags set from AP_OUT_FLAGS
17
+ (the PiPL uses the same flags); Smart Render handled when promised; no mutable
18
+ globals/statics with multi-frame rendering; params read with the right union member;
19
+ 16-bpc white is 32768, not 65535; no sleeping, network or process calls in src/; no
20
+ Adobe SDK files or text copied into the project. Each finding names file:line.
21
+ Silence a false alarm on one line with \`// ap-check: allow <code>\`.`,flags:{types:{type:"boolean"},"types-all":{type:"boolean"}},async run(n,t){const s=l(n),e=await c(s),a=await h(n,s,e);e.errors.push.apply(e.errors,a.errors),e.warnings.push.apply(e.warnings,a.warnings),p(n.out,e);const i=!!t.flags["types-all"];return(i||t.flags.types)&&(n.out.log(""),u(d(s),i,g(s)).forEach((r,o)=>n.out.log(o===1?n.out.style.dim(r):r))),e.errors.length?1:0}};
@@ -0,0 +1,6 @@
1
+ "use strict";const{createGroupCommand:i,number:t,numberList:r}=require("../agent/cli-group"),{UsageError:n}=require("../errors");module.exports=i({name:"comp",summary:"Render After Effects composition frames to PNG files",description:`Renders frames of an After Effects composition at full quality and saves them as
2
+ PNG files (dist-dev/shots/ unless --out), to check what an effect or a script did.
3
+ Works through the project's panel, or the dev bridge for projects without panels.`,subcommands:[{name:"capture",tool:"comp_capture",summary:"Renders frames of a composition (default: the active one, at its current time)",usage:"ap comp capture [--comp <name> | --comp-id <id>] [--frames 0,15,30] [--seconds 0.5,1] [--max-size <px>] [--no-purge] [--keep32] [--out <file.png>] [--timeout-ms 60000]",details:`Up to 12 times per run (seconds first, then frames). --max-size shrinks the saved images (default 1920 for one frame,
4
+ 960 for several); the render itself is full resolution. Caches are purged first so every frame comes from the loaded
5
+ build (--no-purge keeps them). 32-bpc projects render at 16 bpc unless --keep32 (32-bpc PNGs come out too dark).
6
+ With --out and several frames, files are numbered: shot-1.png, shot-2.png...`,flags:{comp:{type:"string",alias:"c"},"comp-id":{type:"string"},frames:{type:"string"},seconds:{type:"string"},"max-size":{type:"string"},"no-purge":{type:"boolean"},keep32:{type:"boolean"},panel:{type:"string",alias:"p"},"timeout-ms":{type:"string"}},image:!0,label:"comp",input:(e,o)=>{if(o.length)throw new n("Unexpected "+JSON.stringify(o[0])+". Name the composition with --comp.");if(e.comp!==void 0&&e["comp-id"]!==void 0)throw new n("Pass --comp or --comp-id, not both.");const s=t(e["comp-id"],"--comp-id");return{comp:s!==void 0?s:e.comp,frames:r(e.frames,"--frames"),seconds:r(e.seconds,"--seconds"),maxSize:t(e["max-size"],"--max-size"),purge:e["no-purge"]?!1:void 0,keep32:e.keep32||void 0,panel:e.panel,timeoutMs:t(e["timeout-ms"],"--timeout-ms")}}}]});