ae-agent-skills 0.2.7 → 0.3.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.
package/CSXS/manifest.xml CHANGED
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <ExtensionManifest Version="7.0" ExtensionBundleId="com.yumehiko.aeagentskill" ExtensionBundleVersion="0.2.7" ExtensionBundleName="ae-agent-skill" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2
+ <ExtensionManifest Version="7.0" ExtensionBundleId="com.yumehiko.aeagentskill" ExtensionBundleVersion="0.3.0" ExtensionBundleName="ae-agent-skill" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
3
  <ExtensionList>
4
- <Extension Id="com.yumehiko.aeagentskill.panel" Version="0.2.7" />
4
+ <Extension Id="com.yumehiko.aeagentskill.panel" Version="0.3.0" />
5
5
  </ExtensionList>
6
6
  <ExecutionEnvironment>
7
7
  <HostList>
package/README.ja.md CHANGED
@@ -1,35 +1,67 @@
1
1
  # ae-agent-skills
2
2
 
3
- `ae-agent-skill`(After Effects CEP パネル)、`ae-cli`、Codex/Gemini 向け skill を1コマンドで導入するリポジトリです。
3
+ `ae-agent-skills`は、コーディングエージェント(Codex / Gemini / Claude Code)からAdobe After Effectsを操作できるようにするためのリポジトリです。
4
+ `ae-agent-skill`(After Effects CEP パネル)、`ae-cli`、エージェント向け skill を導入し、コンポジション作成や既存シーン編集をエージェントに依頼できるようになります。
4
5
 
5
6
  English README: [README.md](README.md)
6
7
 
7
- ## インストール(clone不要)
8
+ ## クイックスタート
9
+
10
+ 1. インストールする。
8
11
 
9
12
  ```bash
10
13
  npx ae-agent-skills install
11
14
  ```
12
15
 
13
- 実行内容:
16
+ 2. After Effects を再起動し、`ウィンドウ > 機能拡張 (ベータ) > ae-agent-skill` を開く。
17
+ 3. Codex、Gemini、または Claude Code を起動し、After Effects操作を依頼する。
18
+
19
+ 最初の依頼例(コンポジション作成):
20
+
21
+ ```text
22
+ $aftereffects-declarative を使って、1920x1080 / 30fps / 5秒のコンポジションを作成して。
23
+ 背景はダークグレー、中央に「Hello AE Agent」のテキストを配置し、
24
+ 0.5秒でフェードインするアニメーションを追加して。
25
+ ```
26
+
27
+ Claude Code では slash command として呼び出します。
28
+
29
+ ```text
30
+ /aftereffects-declarative を使って、1920x1080 / 30fps / 5秒のコンポジションを作成して。
31
+ 背景はダークグレー、中央に「Hello AE Agent」のテキストを配置し、
32
+ 0.5秒でフェードインするアニメーションを追加して。
33
+ ```
34
+
35
+ 4. エージェントの処理完了後、After Effects 上でコンポジションが作成されたことを確認する。
36
+
37
+ エージェントを明示してインストールする場合:
38
+
39
+ ```bash
40
+ npx ae-agent-skills install --agent codex
41
+ npx ae-agent-skills install --agent gemini
42
+ npx ae-agent-skills install --agent claude
43
+ npx ae-agent-skills install --agent all
44
+ ```
45
+
46
+ ## インストール時に行われること
14
47
 
15
- 1. `--agent` 未指定なら、`codex` / `gemini` / `both` の選択を表示します。
48
+ 1. `--agent` 未指定なら、`codex` / `gemini` / `claude` / `both` / `all` の選択を表示します。
16
49
  2. 署名済み ZXP を `UPIA` または `ExManCmd` でインストールします。
17
50
  3. `ae-cli` と agent skill をインストールします。
18
51
  4. `~/ae-agent-skills/` を初期化し、`work/`・`done/`・`scene.schema.json`・`references/` を配置します。
19
52
 
20
- ## エージェントで実行
53
+ `both` は後方互換のため Codex + Gemini、`all` は Codex + Gemini + Claude Code です。
54
+ Claude Code の個人 skill は `~/.claude/skills/<skill-name>/SKILL.md` にインストールされます。
55
+ Claude Code 用の slash command は `~/.claude/commands/<command>.md` にインストールされます。
21
56
 
22
- 導入後:
57
+ ## どの skill を使うか
23
58
 
24
- 1. After Effects を再起動する。
25
- 2. `ウィンドウ > 機能拡張 (ベータ) > ae-agent-skill` を開く。
26
- 3. コーディングエージェントで以下の skill を呼び出す。
27
- - `$aftereffects-declarative`(通常の構成作成向け)
28
- - `$aftereffects-cli`(個別編集・デバッグ向け)
59
+ - `$aftereffects-declarative`: 新規コンポジション作成や全体構成を作るとき(通常はこちら)
60
+ - `$aftereffects-cli`: 既存シーンの一部修正、プロパティ単位の調整、デバッグ
29
61
 
30
62
  ## ドキュメント
31
63
 
32
64
  - CLI利用方法: [docs/cli.ja.md](docs/cli.ja.md)
33
65
  - 開発者向け情報: [docs/development.ja.md](docs/development.ja.md)
34
- - 宣言型 skill 本体: [.codex/skills/aftereffects-declarative/SKILL.md](.codex/skills/aftereffects-declarative/SKILL.md)
35
- - レガシーCLI skill 本体: [.codex/skills/aftereffects-cli/SKILL.md](.codex/skills/aftereffects-cli/SKILL.md)
66
+ - 宣言型 skill 本体: [templates/skills/aftereffects-declarative.SKILL.md](templates/skills/aftereffects-declarative.SKILL.md)
67
+ - CLI skill 本体: [templates/skills/aftereffects-cli.SKILL.md](templates/skills/aftereffects-cli.SKILL.md)
package/README.md CHANGED
@@ -1,35 +1,67 @@
1
1
  # ae-agent-skills
2
2
 
3
- One-command installer for `ae-agent-skill` (After Effects CEP panel), `ae-cli`, and Codex/Gemini skills.
3
+ `ae-agent-skills` enables coding agents (Codex / Gemini / Claude Code) to operate Adobe After Effects.
4
+ It installs `ae-agent-skill` (After Effects CEP panel), `ae-cli`, and agent skills so you can ask your agent to create compositions or edit existing scenes.
4
5
 
5
6
  Japanese README: [README.ja.md](README.ja.md)
6
7
 
7
- ## Install (No clone)
8
+ ## Quick Start
9
+
10
+ 1. Install:
8
11
 
9
12
  ```bash
10
13
  npx ae-agent-skills install
11
14
  ```
12
15
 
13
- What happens:
16
+ 2. Restart After Effects, then open `Window > Extensions (Beta) > ae-agent-skill`.
17
+ 3. Launch Codex, Gemini, or Claude Code and ask it to perform an After Effects task.
18
+
19
+ First request example (create a composition):
20
+
21
+ ```text
22
+ Use $aftereffects-declarative to create a 1920x1080, 30fps, 5-second composition.
23
+ Set a dark gray background, place "Hello AE Agent" text at the center,
24
+ and add a 0.5-second fade-in animation.
25
+ ```
26
+
27
+ In Claude Code, invoke the skill as a slash command:
28
+
29
+ ```text
30
+ Use /aftereffects-declarative to create a 1920x1080, 30fps, 5-second composition.
31
+ Set a dark gray background, place "Hello AE Agent" text at the center,
32
+ and add a 0.5-second fade-in animation.
33
+ ```
34
+
35
+ 4. After the agent finishes, confirm the composition is created in After Effects.
36
+
37
+ To choose an agent explicitly:
38
+
39
+ ```bash
40
+ npx ae-agent-skills install --agent codex
41
+ npx ae-agent-skills install --agent gemini
42
+ npx ae-agent-skills install --agent claude
43
+ npx ae-agent-skills install --agent all
44
+ ```
45
+
46
+ ## What the installer does
14
47
 
15
- 1. The installer asks which agent to configure (`codex` / `gemini` / `both`) if `--agent` is omitted.
16
- 2. It installs the signed ZXP extension via `UPIA` or `ExManCmd`.
17
- 3. It installs `ae-cli` and agent skills.
18
- 4. It initializes `~/ae-agent-skills/` with `work/`, `done/`, `scene.schema.json`, and `references/`.
48
+ 1. Prompts for target agent (`codex` / `gemini` / `claude` / `both` / `all`) when `--agent` is omitted.
49
+ 2. Installs the signed ZXP extension via `UPIA` or `ExManCmd`.
50
+ 3. Installs `ae-cli` and agent skills.
51
+ 4. Initializes `~/ae-agent-skills/` with `work/`, `done/`, `scene.schema.json`, and `references/`.
19
52
 
20
- ## Run with your agent
53
+ `both` means Codex + Gemini for backward compatibility. `all` means Codex + Gemini + Claude Code.
54
+ Claude Code user skills are installed under `~/.claude/skills/<skill-name>/SKILL.md`.
55
+ Claude Code slash commands are installed under `~/.claude/commands/<command>.md`.
21
56
 
22
- After installation:
57
+ ## Which skill to use
23
58
 
24
- 1. Restart After Effects.
25
- 2. Open `Window > Extensions (Beta) > ae-agent-skill`.
26
- 3. Run your coding agent and call one of these skills:
27
- - `$aftereffects-declarative` for normal composition building.
28
- - `$aftereffects-cli` for command-by-command edits/debug.
59
+ - `$aftereffects-declarative`: default for new composition building and overall scene structure
60
+ - `$aftereffects-cli`: best for surgical edits, property-level tweaks, and debugging
29
61
 
30
62
  ## Docs
31
63
 
32
64
  - CLI usage: [docs/cli.md](docs/cli.md)
33
65
  - Development: [docs/development.md](docs/development.md)
34
- - Declarative skill source: [.codex/skills/aftereffects-declarative/SKILL.md](.codex/skills/aftereffects-declarative/SKILL.md)
35
- - Legacy CLI skill source: [.codex/skills/aftereffects-cli/SKILL.md](.codex/skills/aftereffects-cli/SKILL.md)
66
+ - Declarative skill source: [templates/skills/aftereffects-declarative.SKILL.md](templates/skills/aftereffects-declarative.SKILL.md)
67
+ - CLI skill source: [templates/skills/aftereffects-cli.SKILL.md](templates/skills/aftereffects-cli.SKILL.md)
@@ -0,0 +1,453 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import readline from 'node:readline';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ export const DEFAULT_REPO = 'yumehiko/ae-agent-skills';
9
+ export const AGENT_WORKSPACE_NAME = 'ae-agent-skills';
10
+
11
+ export const SKILL_SOURCES = [
12
+ { sourceName: 'aftereffects-cli.SKILL.md', destinationName: 'aftereffects-cli' },
13
+ { sourceName: 'aftereffects-declarative.SKILL.md', destinationName: 'aftereffects-declarative' },
14
+ ];
15
+
16
+ export const CLAUDE_COMMAND_SOURCES = [
17
+ { sourceName: 'aftereffects-cli.md', destinationName: 'aftereffects-cli.md' },
18
+ { sourceName: 'aftereffects-declarative.md', destinationName: 'aftereffects-declarative.md' },
19
+ ];
20
+
21
+ export const WORKSPACE_RESOURCE_SOURCES = [
22
+ { source: ['schemas', 'scene.schema.json'], destination: ['scene.schema.json'] },
23
+ { source: ['examples', 'scene.example.json'], destination: ['references', 'scene.example.json'] },
24
+ { source: ['docs', 'cli.ja.md'], destination: ['references', 'cli.ja.md'] },
25
+ { source: ['docs', 'cli.md'], destination: ['references', 'cli.md'] },
26
+ ];
27
+
28
+ export const AGENT_REGISTRY = [
29
+ {
30
+ id: 'codex',
31
+ destRoot({ home, env }) {
32
+ const codexHome = env.CODEX_HOME || path.join(home, '.codex');
33
+ return path.join(codexHome, 'skills');
34
+ },
35
+ isDetected({ home, env, fsModule }) {
36
+ return Boolean(env.CODEX_HOME) || fsModule.existsSync(path.join(home, '.codex'));
37
+ },
38
+ },
39
+ {
40
+ id: 'gemini',
41
+ destRoot({ home }) {
42
+ return path.join(home, '.gemini', 'skills');
43
+ },
44
+ isDetected({ home, fsModule }) {
45
+ return fsModule.existsSync(path.join(home, '.gemini'));
46
+ },
47
+ },
48
+ {
49
+ id: 'claude',
50
+ destRoot({ home }) {
51
+ return path.join(home, '.claude', 'skills');
52
+ },
53
+ commandsRoot({ home }) {
54
+ return path.join(home, '.claude', 'commands');
55
+ },
56
+ isDetected({ home, fsModule }) {
57
+ return fsModule.existsSync(path.join(home, '.claude'));
58
+ },
59
+ },
60
+ ];
61
+
62
+ const AGENT_ALIASES = {
63
+ both: ['codex', 'gemini'],
64
+ all: AGENT_REGISTRY.map((agent) => agent.id),
65
+ };
66
+
67
+ export function getRepoRoot() {
68
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
69
+ }
70
+
71
+ export function printHelp(output = console.log) {
72
+ output(`ae-agent-setup
73
+
74
+ Usage:
75
+ ae-agent-setup install [options]
76
+
77
+ Options:
78
+ --agent <codex|gemini|claude|both|all>
79
+ Agent target. If omitted, interactive selection is shown.
80
+ "both" means codex+gemini for backward compatibility.
81
+ "all" means codex+gemini+claude.
82
+ --repo <owner/repo> GitHub repository for release and CLI install (default: ${DEFAULT_REPO}).
83
+ --zxp <path-or-url> Local ZXP path or direct download URL.
84
+ --skip-extension Skip ZXP extension installation.
85
+ --skip-cli Skip ae-cli installation.
86
+ --skip-skills Skip skill installation.
87
+ -h, --help Show this help.
88
+ `);
89
+ }
90
+
91
+ export function parseArgs(argv) {
92
+ const opts = {
93
+ agent: '',
94
+ repo: DEFAULT_REPO,
95
+ zxp: '',
96
+ skipExtension: false,
97
+ skipCli: false,
98
+ skipSkills: false,
99
+ };
100
+
101
+ for (let i = 0; i < argv.length; i += 1) {
102
+ const arg = argv[i];
103
+ if (arg === '--agent') {
104
+ opts.agent = argv[i + 1] || '';
105
+ i += 1;
106
+ continue;
107
+ }
108
+ if (arg === '--repo') {
109
+ opts.repo = argv[i + 1] || '';
110
+ i += 1;
111
+ continue;
112
+ }
113
+ if (arg === '--zxp') {
114
+ opts.zxp = argv[i + 1] || '';
115
+ i += 1;
116
+ continue;
117
+ }
118
+ if (arg === '--skip-extension') {
119
+ opts.skipExtension = true;
120
+ continue;
121
+ }
122
+ if (arg === '--skip-cli') {
123
+ opts.skipCli = true;
124
+ continue;
125
+ }
126
+ if (arg === '--skip-skills') {
127
+ opts.skipSkills = true;
128
+ continue;
129
+ }
130
+ if (arg === '-h' || arg === '--help') {
131
+ opts.help = true;
132
+ continue;
133
+ }
134
+ throw new Error(`Unknown argument: ${arg}`);
135
+ }
136
+
137
+ return opts;
138
+ }
139
+
140
+ export function expandAgentTarget(agentArg) {
141
+ const value = String(agentArg || '').toLowerCase();
142
+ const direct = AGENT_REGISTRY.find((agent) => agent.id === value);
143
+ if (direct) return [direct.id];
144
+ if (AGENT_ALIASES[value]) return [...AGENT_ALIASES[value]];
145
+ throw new Error(`Invalid --agent value: ${agentArg}`);
146
+ }
147
+
148
+ export function getDetectedAgents({ home = os.homedir(), env = process.env, fsModule = fs } = {}) {
149
+ return AGENT_REGISTRY
150
+ .filter((agent) => agent.isDetected({ home, env, fsModule }))
151
+ .map((agent) => agent.id);
152
+ }
153
+
154
+ export function getSkillInstallTargets(
155
+ agentArg,
156
+ { home = os.homedir(), env = process.env } = {},
157
+ ) {
158
+ return expandAgentTarget(agentArg).map((agentId) => {
159
+ const agent = AGENT_REGISTRY.find((entry) => entry.id === agentId);
160
+ return {
161
+ kind: agent.id,
162
+ destRoot: agent.destRoot({ home, env }),
163
+ };
164
+ });
165
+ }
166
+
167
+ export function getClaudeCommandInstallTarget({ home = os.homedir() } = {}) {
168
+ const claude = AGENT_REGISTRY.find((entry) => entry.id === 'claude');
169
+ return claude.commandsRoot({ home });
170
+ }
171
+
172
+ function ask(question) {
173
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
174
+ return new Promise((resolve) => {
175
+ rl.question(question, (answer) => {
176
+ rl.close();
177
+ resolve(answer.trim());
178
+ });
179
+ });
180
+ }
181
+
182
+ export async function resolveAgent(agentArg) {
183
+ if (agentArg) {
184
+ expandAgentTarget(agentArg);
185
+ return agentArg.toLowerCase();
186
+ }
187
+
188
+ const detected = getDetectedAgents();
189
+ const recommended = detected[0] || 'codex';
190
+ console.log('Select which coding agent should receive skills:');
191
+ console.log(` 1) codex${recommended === 'codex' ? ' (recommended)' : ''}`);
192
+ console.log(` 2) gemini${recommended === 'gemini' ? ' (recommended)' : ''}`);
193
+ console.log(` 3) claude${recommended === 'claude' ? ' (recommended)' : ''}`);
194
+ console.log(' 4) both (codex + gemini)');
195
+ console.log(' 5) all (codex + gemini + claude)');
196
+
197
+ if (!process.stdin.isTTY) {
198
+ console.log(`No interactive terminal detected. Defaulting to: ${recommended}`);
199
+ return recommended;
200
+ }
201
+
202
+ const answer = await ask('Enter 1, 2, 3, 4, or 5 [1]: ');
203
+ if (!answer || answer === '1') return 'codex';
204
+ if (answer === '2') return 'gemini';
205
+ if (answer === '3') return 'claude';
206
+ if (answer === '4') return 'both';
207
+ if (answer === '5') return 'all';
208
+ throw new Error(`Invalid selection: ${answer}`);
209
+ }
210
+
211
+ export function run(cmd, args, options = {}) {
212
+ const pretty = `${cmd} ${args.join(' ')}`.trim();
213
+ console.log(`$ ${pretty}`);
214
+ const res = spawnSync(cmd, args, { stdio: 'inherit', ...options });
215
+ if (res.error) {
216
+ throw new Error(`Command failed: ${pretty}\n${res.error.message}`);
217
+ }
218
+ if (res.status !== 0) {
219
+ throw new Error(`Command failed with exit code ${res.status}: ${pretty}`);
220
+ }
221
+ }
222
+
223
+ export function commandExists(cmd) {
224
+ const res = spawnSync('which', [cmd], { stdio: 'pipe', encoding: 'utf8' });
225
+ return res.status === 0;
226
+ }
227
+
228
+ export function detectInstaller() {
229
+ if (commandExists('upia')) return { cmd: 'upia', args: ['--install'] };
230
+ if (commandExists('UPIA')) return { cmd: 'UPIA', args: ['--install'] };
231
+
232
+ const knownUpiaPaths = [
233
+ '/Library/Application Support/Adobe/Adobe Desktop Common/RemoteComponents/UPI/UnifiedPluginInstallerAgent/UnifiedPluginInstallerAgent.app/Contents/MacOS/UnifiedPluginInstallerAgent',
234
+ '/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/UPIA/UnifiedPluginInstallerAgent',
235
+ ];
236
+ for (const knownUpiaPath of knownUpiaPaths) {
237
+ if (fs.existsSync(knownUpiaPath)) return { cmd: knownUpiaPath, args: ['--install'] };
238
+ }
239
+
240
+ if (commandExists('ExManCmd')) return { cmd: 'ExManCmd', args: ['--install'] };
241
+ return null;
242
+ }
243
+
244
+ function fetchJson(url) {
245
+ return new Promise((resolve, reject) => {
246
+ const req = fetch(url, {
247
+ headers: {
248
+ Accept: 'application/vnd.github+json',
249
+ 'User-Agent': 'ae-agent-setup',
250
+ },
251
+ });
252
+ req.then(async (res) => {
253
+ if (!res.ok) {
254
+ reject(new Error(`Request failed: ${res.status} ${res.statusText}`));
255
+ return;
256
+ }
257
+ try {
258
+ const body = await res.json();
259
+ resolve(body);
260
+ } catch (err) {
261
+ reject(err);
262
+ }
263
+ }).catch(reject);
264
+ });
265
+ }
266
+
267
+ function downloadToFile(url, destination) {
268
+ return fetch(url, {
269
+ headers: {
270
+ Accept: 'application/octet-stream',
271
+ 'User-Agent': 'ae-agent-setup',
272
+ },
273
+ }).then(async (res) => {
274
+ if (!res.ok) {
275
+ throw new Error(`Download failed: ${res.status} ${res.statusText}`);
276
+ }
277
+ const data = Buffer.from(await res.arrayBuffer());
278
+ fs.writeFileSync(destination, data);
279
+ return destination;
280
+ });
281
+ }
282
+
283
+ export async function resolveZxpPath(opts) {
284
+ if (opts.zxp) {
285
+ if (opts.zxp.startsWith('http://') || opts.zxp.startsWith('https://')) {
286
+ const output = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ae-agent-zxp-')), 'extension.zxp');
287
+ console.log(`Downloading ZXP from URL: ${opts.zxp}`);
288
+ await downloadToFile(opts.zxp, output);
289
+ return output;
290
+ }
291
+
292
+ const local = path.resolve(process.cwd(), opts.zxp);
293
+ if (!fs.existsSync(local)) {
294
+ throw new Error(`ZXP not found: ${local}`);
295
+ }
296
+ return local;
297
+ }
298
+
299
+ console.log(`Fetching latest release from GitHub: ${opts.repo}`);
300
+ const release = await fetchJson(`https://api.github.com/repos/${opts.repo}/releases/latest`);
301
+ const asset = (release.assets || []).find((a) => typeof a.name === 'string' && a.name.endsWith('.zxp'));
302
+ if (!asset) {
303
+ throw new Error(`No .zxp asset found in latest release of ${opts.repo}`);
304
+ }
305
+
306
+ const output = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ae-agent-zxp-')), asset.name);
307
+ console.log(`Downloading asset: ${asset.name}`);
308
+ await downloadToFile(asset.browser_download_url, output);
309
+ return output;
310
+ }
311
+
312
+ export function installSkills(
313
+ agent,
314
+ { root = getRepoRoot(), home = os.homedir(), env = process.env } = {},
315
+ ) {
316
+ const sourceRoot = path.join(root, 'templates', 'skills');
317
+ const targets = getSkillInstallTargets(agent, { home, env });
318
+
319
+ for (const target of targets) {
320
+ fs.mkdirSync(target.destRoot, { recursive: true });
321
+ for (const skill of SKILL_SOURCES) {
322
+ const source = path.join(sourceRoot, skill.sourceName);
323
+ const destination = path.join(target.destRoot, skill.destinationName);
324
+ if (!fs.existsSync(source)) {
325
+ throw new Error(`Skill source not found: ${source}`);
326
+ }
327
+ fs.rmSync(destination, { recursive: true, force: true });
328
+ fs.mkdirSync(destination, { recursive: true });
329
+ fs.copyFileSync(source, path.join(destination, 'SKILL.md'));
330
+ console.log(`Installed ${target.kind} skill: ${destination}`);
331
+ }
332
+ }
333
+
334
+ if (expandAgentTarget(agent).includes('claude')) {
335
+ installClaudeCommands({ root, home });
336
+ }
337
+ }
338
+
339
+ export function installClaudeCommands({ root = getRepoRoot(), home = os.homedir() } = {}) {
340
+ const sourceRoot = path.join(root, 'templates', 'claude', 'commands');
341
+ const destRoot = getClaudeCommandInstallTarget({ home });
342
+ fs.mkdirSync(destRoot, { recursive: true });
343
+
344
+ for (const command of CLAUDE_COMMAND_SOURCES) {
345
+ const source = path.join(sourceRoot, command.sourceName);
346
+ const destination = path.join(destRoot, command.destinationName);
347
+ if (!fs.existsSync(source)) {
348
+ throw new Error(`Claude command source not found: ${source}`);
349
+ }
350
+ fs.copyFileSync(source, destination);
351
+ console.log(`Installed claude command: ${destination}`);
352
+ }
353
+ }
354
+
355
+ export function setupAgentWorkspace({ root = getRepoRoot(), home = os.homedir() } = {}) {
356
+ const workspaceRoot = path.join(home, AGENT_WORKSPACE_NAME);
357
+ const workDir = path.join(workspaceRoot, 'work');
358
+ const doneDir = path.join(workspaceRoot, 'done');
359
+ const refsDir = path.join(workspaceRoot, 'references');
360
+
361
+ fs.mkdirSync(workDir, { recursive: true });
362
+ fs.mkdirSync(doneDir, { recursive: true });
363
+ fs.mkdirSync(refsDir, { recursive: true });
364
+
365
+ for (const resource of WORKSPACE_RESOURCE_SOURCES) {
366
+ const source = path.join(root, ...resource.source);
367
+ const destination = path.join(workspaceRoot, ...resource.destination);
368
+ if (!fs.existsSync(source)) {
369
+ throw new Error(`Workspace resource not found: ${source}`);
370
+ }
371
+ fs.copyFileSync(source, destination);
372
+ }
373
+
374
+ console.log(`Prepared workspace: ${workspaceRoot}`);
375
+ }
376
+
377
+ export function installCli(repo) {
378
+ if (!commandExists('python3')) {
379
+ throw new Error('python3 is required to install ae-cli.');
380
+ }
381
+ const spec = `git+https://github.com/${repo}.git`;
382
+ run('python3', ['-m', 'pip', 'install', '--user', '--upgrade', spec]);
383
+
384
+ const helpRes = spawnSync('ae-cli', ['--help'], { stdio: 'inherit' });
385
+ if (helpRes.status !== 0) {
386
+ console.log('ae-cli was installed, but not found on PATH.');
387
+ console.log('Run this once in your shell profile if needed:');
388
+ console.log(' export PATH="$HOME/Library/Python/3.*/bin:$PATH"');
389
+ }
390
+ }
391
+
392
+ export async function installCommand(opts) {
393
+ console.log('Starting ae-agent setup...');
394
+ setupAgentWorkspace();
395
+
396
+ const agent = await resolveAgent(opts.agent);
397
+ console.log(`Selected agent target: ${agent}`);
398
+
399
+ if (!opts.skipExtension) {
400
+ const installer = detectInstaller();
401
+ if (!installer) {
402
+ throw new Error('Neither UPIA nor ExManCmd was found. Install one of them and run again.');
403
+ }
404
+
405
+ const zxpPath = await resolveZxpPath(opts);
406
+ console.log(`Installing extension via ${installer.cmd}...`);
407
+ run(installer.cmd, [...installer.args, zxpPath]);
408
+ } else {
409
+ console.log('Skipping extension installation (--skip-extension).');
410
+ }
411
+
412
+ if (!opts.skipCli) {
413
+ console.log('Installing ae-cli...');
414
+ installCli(opts.repo);
415
+ } else {
416
+ console.log('Skipping ae-cli installation (--skip-cli).');
417
+ }
418
+
419
+ if (!opts.skipSkills) {
420
+ console.log('Installing agent skills...');
421
+ installSkills(agent);
422
+ } else {
423
+ console.log('Skipping skill installation (--skip-skills).');
424
+ }
425
+
426
+ console.log('Setup finished.');
427
+ console.log('Next actions:');
428
+ console.log(' 1) Fully restart After Effects.');
429
+ console.log(' 2) Open the panel: Window > Extensions (Beta) > ae-agent-skill.');
430
+ console.log(' 3) Run: ae-cli health');
431
+ console.log(` 4) Use workspace: ${path.join(os.homedir(), AGENT_WORKSPACE_NAME)}`);
432
+ }
433
+
434
+ export async function main(argv = process.argv.slice(2)) {
435
+ const [command, ...rest] = argv;
436
+
437
+ if (!command || command === '-h' || command === '--help') {
438
+ printHelp();
439
+ return;
440
+ }
441
+
442
+ if (command !== 'install') {
443
+ throw new Error(`Unknown command: ${command}`);
444
+ }
445
+
446
+ const opts = parseArgs(rest);
447
+ if (opts.help) {
448
+ printHelp();
449
+ return;
450
+ }
451
+
452
+ await installCommand(opts);
453
+ }
@@ -1,367 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { spawnSync } from 'node:child_process';
7
- import readline from 'node:readline';
8
- import { fileURLToPath } from 'node:url';
9
-
10
- const DEFAULT_REPO = 'yumehiko/ae-agent-skills';
11
- const AGENT_WORKSPACE_NAME = 'ae-agent-skills';
12
- const SKILL_SOURCES = [
13
- { sourceName: 'aftereffects-cli.SKILL.md', destinationName: 'aftereffects-cli' },
14
- { sourceName: 'aftereffects-declarative.SKILL.md', destinationName: 'aftereffects-declarative' },
15
- ];
16
- const WORKSPACE_RESOURCE_SOURCES = [
17
- { source: ['schemas', 'scene.schema.json'], destination: ['scene.schema.json'] },
18
- { source: ['examples', 'scene.example.json'], destination: ['references', 'scene.example.json'] },
19
- { source: ['docs', 'cli.ja.md'], destination: ['references', 'cli.ja.md'] },
20
- { source: ['docs', 'cli.md'], destination: ['references', 'cli.md'] },
21
- ];
22
-
23
- function printHelp() {
24
- console.log(`ae-agent-setup
25
-
26
- Usage:
27
- ae-agent-setup install [options]
28
-
29
- Options:
30
- --agent <codex|gemini|both> Agent target. If omitted, interactive selection is shown.
31
- --repo <owner/repo> GitHub repository for release and CLI install (default: ${DEFAULT_REPO}).
32
- --zxp <path-or-url> Local ZXP path or direct download URL.
33
- --skip-extension Skip ZXP extension installation.
34
- --skip-cli Skip ae-cli installation.
35
- --skip-skills Skip skill installation.
36
- -h, --help Show this help.
37
- `);
38
- }
39
-
40
- function run(cmd, args, options = {}) {
41
- const pretty = `${cmd} ${args.join(' ')}`.trim();
42
- console.log(`$ ${pretty}`);
43
- const res = spawnSync(cmd, args, { stdio: 'inherit', ...options });
44
- if (res.error) {
45
- throw new Error(`Command failed: ${pretty}\n${res.error.message}`);
46
- }
47
- if (res.status !== 0) {
48
- throw new Error(`Command failed with exit code ${res.status}: ${pretty}`);
49
- }
50
- }
51
-
52
- function commandExists(cmd) {
53
- const res = spawnSync('which', [cmd], { stdio: 'pipe', encoding: 'utf8' });
54
- return res.status === 0;
55
- }
56
-
57
- function detectInstaller() {
58
- if (commandExists('upia')) return { cmd: 'upia', args: ['--install'] };
59
- if (commandExists('UPIA')) return { cmd: 'UPIA', args: ['--install'] };
60
-
61
- const knownUpiaPaths = [
62
- '/Library/Application Support/Adobe/Adobe Desktop Common/RemoteComponents/UPI/UnifiedPluginInstallerAgent/UnifiedPluginInstallerAgent.app/Contents/MacOS/UnifiedPluginInstallerAgent',
63
- '/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/UPIA/UnifiedPluginInstallerAgent',
64
- ];
65
- for (const knownUpiaPath of knownUpiaPaths) {
66
- if (fs.existsSync(knownUpiaPath)) return { cmd: knownUpiaPath, args: ['--install'] };
67
- }
68
-
69
- if (commandExists('ExManCmd')) return { cmd: 'ExManCmd', args: ['--install'] };
70
- return null;
71
- }
72
-
73
- function parseArgs(argv) {
74
- const opts = {
75
- agent: '',
76
- repo: DEFAULT_REPO,
77
- zxp: '',
78
- skipExtension: false,
79
- skipCli: false,
80
- skipSkills: false,
81
- };
82
-
83
- for (let i = 0; i < argv.length; i += 1) {
84
- const arg = argv[i];
85
- if (arg === '--agent') {
86
- opts.agent = argv[i + 1] || '';
87
- i += 1;
88
- continue;
89
- }
90
- if (arg === '--repo') {
91
- opts.repo = argv[i + 1] || '';
92
- i += 1;
93
- continue;
94
- }
95
- if (arg === '--zxp') {
96
- opts.zxp = argv[i + 1] || '';
97
- i += 1;
98
- continue;
99
- }
100
- if (arg === '--skip-extension') {
101
- opts.skipExtension = true;
102
- continue;
103
- }
104
- if (arg === '--skip-cli') {
105
- opts.skipCli = true;
106
- continue;
107
- }
108
- if (arg === '--skip-skills') {
109
- opts.skipSkills = true;
110
- continue;
111
- }
112
- if (arg === '-h' || arg === '--help') {
113
- opts.help = true;
114
- continue;
115
- }
116
- throw new Error(`Unknown argument: ${arg}`);
117
- }
118
-
119
- return opts;
120
- }
121
-
122
- function getDetectedAgents() {
123
- const detected = [];
124
- const home = os.homedir();
125
- if (process.env.CODEX_HOME || fs.existsSync(path.join(home, '.codex'))) detected.push('codex');
126
- if (fs.existsSync(path.join(home, '.gemini'))) detected.push('gemini');
127
- return detected;
128
- }
129
-
130
- function ask(question) {
131
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
132
- return new Promise((resolve) => {
133
- rl.question(question, (answer) => {
134
- rl.close();
135
- resolve(answer.trim());
136
- });
137
- });
138
- }
139
-
140
- async function resolveAgent(agentArg) {
141
- if (agentArg) {
142
- const value = agentArg.toLowerCase();
143
- if (!['codex', 'gemini', 'both'].includes(value)) {
144
- throw new Error(`Invalid --agent value: ${agentArg}`);
145
- }
146
- return value;
147
- }
148
-
149
- const detected = getDetectedAgents();
150
- const recommended = detected[0] || 'codex';
151
- console.log('Select which coding agent should receive skills:');
152
- console.log(` 1) codex${recommended === 'codex' ? ' (recommended)' : ''}`);
153
- console.log(` 2) gemini${recommended === 'gemini' ? ' (recommended)' : ''}`);
154
- console.log(' 3) both');
155
-
156
- if (!process.stdin.isTTY) {
157
- console.log(`No interactive terminal detected. Defaulting to: ${recommended}`);
158
- return recommended;
159
- }
160
-
161
- const answer = await ask('Enter 1, 2, or 3 [1]: ');
162
- if (!answer || answer === '1') return 'codex';
163
- if (answer === '2') return 'gemini';
164
- if (answer === '3') return 'both';
165
- throw new Error(`Invalid selection: ${answer}`);
166
- }
167
-
168
- function fetchJson(url) {
169
- return new Promise((resolve, reject) => {
170
- const req = fetch(url, {
171
- headers: {
172
- Accept: 'application/vnd.github+json',
173
- 'User-Agent': 'ae-agent-setup',
174
- },
175
- });
176
- req.then(async (res) => {
177
- if (!res.ok) {
178
- reject(new Error(`Request failed: ${res.status} ${res.statusText}`));
179
- return;
180
- }
181
- try {
182
- const body = await res.json();
183
- resolve(body);
184
- } catch (err) {
185
- reject(err);
186
- }
187
- }).catch(reject);
188
- });
189
- }
190
-
191
- function downloadToFile(url, destination) {
192
- return fetch(url, {
193
- headers: {
194
- Accept: 'application/octet-stream',
195
- 'User-Agent': 'ae-agent-setup',
196
- },
197
- }).then(async (res) => {
198
- if (!res.ok) {
199
- throw new Error(`Download failed: ${res.status} ${res.statusText}`);
200
- }
201
- const data = Buffer.from(await res.arrayBuffer());
202
- fs.writeFileSync(destination, data);
203
- return destination;
204
- });
205
- }
206
-
207
- async function resolveZxpPath(opts) {
208
- if (opts.zxp) {
209
- if (opts.zxp.startsWith('http://') || opts.zxp.startsWith('https://')) {
210
- const output = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ae-agent-zxp-')), 'extension.zxp');
211
- console.log(`Downloading ZXP from URL: ${opts.zxp}`);
212
- await downloadToFile(opts.zxp, output);
213
- return output;
214
- }
215
-
216
- const local = path.resolve(process.cwd(), opts.zxp);
217
- if (!fs.existsSync(local)) {
218
- throw new Error(`ZXP not found: ${local}`);
219
- }
220
- return local;
221
- }
222
-
223
- console.log(`Fetching latest release from GitHub: ${opts.repo}`);
224
- const release = await fetchJson(`https://api.github.com/repos/${opts.repo}/releases/latest`);
225
- const asset = (release.assets || []).find((a) => typeof a.name === 'string' && a.name.endsWith('.zxp'));
226
- if (!asset) {
227
- throw new Error(`No .zxp asset found in latest release of ${opts.repo}`);
228
- }
229
-
230
- const output = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ae-agent-zxp-')), asset.name);
231
- console.log(`Downloading asset: ${asset.name}`);
232
- await downloadToFile(asset.browser_download_url, output);
233
- return output;
234
- }
235
-
236
- function installSkills(agent) {
237
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
238
- const sourceRoot = path.join(root, 'templates', 'skills');
239
-
240
- const targets = [];
241
- if (agent === 'codex' || agent === 'both') {
242
- const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
243
- targets.push({ kind: 'codex', destRoot: path.join(codexHome, 'skills') });
244
- }
245
- if (agent === 'gemini' || agent === 'both') {
246
- targets.push({ kind: 'gemini', destRoot: path.join(os.homedir(), '.gemini', 'skills') });
247
- }
248
-
249
- for (const target of targets) {
250
- fs.mkdirSync(target.destRoot, { recursive: true });
251
- for (const skill of SKILL_SOURCES) {
252
- const source = path.join(sourceRoot, skill.sourceName);
253
- const destination = path.join(target.destRoot, skill.destinationName);
254
- if (!fs.existsSync(source)) {
255
- throw new Error(`Skill source not found: ${source}`);
256
- }
257
- fs.rmSync(destination, { recursive: true, force: true });
258
- fs.mkdirSync(destination, { recursive: true });
259
- fs.copyFileSync(source, path.join(destination, 'SKILL.md'));
260
- console.log(`Installed ${target.kind} skill: ${destination}`);
261
- }
262
- }
263
- }
264
-
265
- function setupAgentWorkspace() {
266
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
267
- const workspaceRoot = path.join(os.homedir(), AGENT_WORKSPACE_NAME);
268
- const workDir = path.join(workspaceRoot, 'work');
269
- const doneDir = path.join(workspaceRoot, 'done');
270
- const refsDir = path.join(workspaceRoot, 'references');
271
-
272
- fs.mkdirSync(workDir, { recursive: true });
273
- fs.mkdirSync(doneDir, { recursive: true });
274
- fs.mkdirSync(refsDir, { recursive: true });
275
-
276
- for (const resource of WORKSPACE_RESOURCE_SOURCES) {
277
- const source = path.join(root, ...resource.source);
278
- const destination = path.join(workspaceRoot, ...resource.destination);
279
- if (!fs.existsSync(source)) {
280
- throw new Error(`Workspace resource not found: ${source}`);
281
- }
282
- fs.copyFileSync(source, destination);
283
- }
284
-
285
- console.log(`Prepared workspace: ${workspaceRoot}`);
286
- }
287
-
288
- function installCli(repo) {
289
- if (!commandExists('python3')) {
290
- throw new Error('python3 is required to install ae-cli.');
291
- }
292
- const spec = `git+https://github.com/${repo}.git`;
293
- run('python3', ['-m', 'pip', 'install', '--user', '--upgrade', spec]);
294
-
295
- const helpRes = spawnSync('ae-cli', ['--help'], { stdio: 'inherit' });
296
- if (helpRes.status !== 0) {
297
- console.log('ae-cli was installed, but not found on PATH.');
298
- console.log('Run this once in your shell profile if needed:');
299
- console.log(' export PATH="$HOME/Library/Python/3.*/bin:$PATH"');
300
- }
301
- }
302
-
303
- async function installCommand(opts) {
304
- console.log('Starting ae-agent setup...');
305
- setupAgentWorkspace();
306
-
307
- const agent = await resolveAgent(opts.agent);
308
- console.log(`Selected agent target: ${agent}`);
309
-
310
- if (!opts.skipExtension) {
311
- const installer = detectInstaller();
312
- if (!installer) {
313
- throw new Error('Neither UPIA nor ExManCmd was found. Install one of them and run again.');
314
- }
315
-
316
- const zxpPath = await resolveZxpPath(opts);
317
- console.log(`Installing extension via ${installer.cmd}...`);
318
- run(installer.cmd, [...installer.args, zxpPath]);
319
- } else {
320
- console.log('Skipping extension installation (--skip-extension).');
321
- }
322
-
323
- if (!opts.skipCli) {
324
- console.log('Installing ae-cli...');
325
- installCli(opts.repo);
326
- } else {
327
- console.log('Skipping ae-cli installation (--skip-cli).');
328
- }
329
-
330
- if (!opts.skipSkills) {
331
- console.log('Installing agent skills...');
332
- installSkills(agent);
333
- } else {
334
- console.log('Skipping skill installation (--skip-skills).');
335
- }
336
-
337
- console.log('Setup finished.');
338
- console.log('Next actions:');
339
- console.log(' 1) Fully restart After Effects.');
340
- console.log(' 2) Open the panel: Window > Extensions (Beta) > ae-agent-skill.');
341
- console.log(' 3) Run: ae-cli health');
342
- console.log(` 4) Use workspace: ${path.join(os.homedir(), AGENT_WORKSPACE_NAME)}`);
343
- }
344
-
345
- async function main() {
346
- const [command, ...rest] = process.argv.slice(2);
347
-
348
- if (!command || command === '-h' || command === '--help') {
349
- printHelp();
350
- return;
351
- }
352
-
353
- if (command !== 'install') {
354
- throw new Error(`Unknown command: ${command}`);
355
- }
356
-
357
- const opts = parseArgs(rest);
358
- if (opts.help) {
359
- printHelp();
360
- return;
361
- }
362
-
363
- await installCommand(opts);
364
- }
3
+ import { main } from './ae-agent-setup-lib.mjs';
365
4
 
366
5
  main().catch((err) => {
367
6
  console.error(`ERROR: ${err.message}`);
@@ -22,17 +22,19 @@ defaults write com.adobe.CSXS.11 PlayerDebugMode 1
22
22
 
23
23
  ```bash
24
24
  python3 -m pip install -e ".[dev]"
25
- PYTHONPATH=src pytest
25
+ PYTHONPATH=src python3 -m pytest
26
+ npm run test:node
26
27
  ```
27
28
 
28
29
  ## ZXPビルドと公開手順
29
30
 
30
31
  `0.2.6` 以降は `package.json` の `version` を正として、`npm version` 実行時に `CSXS/manifest.xml` へ自動同期します。
32
+ Python パッケージ版は `pyproject.toml` も同じ値に揃えます。
31
33
 
32
34
  ### 1) バージョン更新
33
35
 
34
36
  ```bash
35
- npm version 0.2.7 --no-git-tag-version
37
+ npm version 0.3.0 --no-git-tag-version
36
38
  ```
37
39
 
38
40
  ### 2) 署名付き ZXP ビルド
@@ -41,6 +43,26 @@ npm version 0.2.7 --no-git-tag-version
41
43
  - `ZXPSignCmd` が `PATH` 上にある、または `ZXPSIGNCMD_BIN` で実体パスを指定できる
42
44
  - 署名証明書 (`.p12`) とパスワードを用意済み
43
45
 
46
+ 1コマンド(パスワードはプロンプト入力):
47
+
48
+ ```bash
49
+ npm run build:zxp
50
+ ```
51
+
52
+ または:
53
+
54
+ ```bash
55
+ ./scripts/signing/build-zxp-interactive.sh
56
+ ```
57
+
58
+ 証明書パスを変える場合:
59
+
60
+ ```bash
61
+ SIGN_CERT_P12=/absolute/path/to/dev-cert.p12 npm run build:zxp
62
+ ```
63
+
64
+ 以下は従来どおり、環境変数で直接指定する方法:
65
+
44
66
  ```bash
45
67
  SIGN_CERT_P12=certs/dev-cert.p12 \
46
68
  SIGN_CERT_PASSWORD='your-password' \
@@ -62,11 +84,11 @@ SIGN_CERT_PASSWORD='your-password' \
62
84
  ### 3) コミット・タグ・push
63
85
 
64
86
  ```bash
65
- git add package.json CSXS/manifest.xml
66
- git commit -m "release: v0.2.7"
67
- git tag v0.2.7
87
+ git add package.json pyproject.toml CSXS/manifest.xml
88
+ git commit -m "release: v0.3.0"
89
+ git tag v0.3.0
68
90
  git push origin HEAD
69
- git push origin v0.2.7
91
+ git push origin v0.3.0
70
92
  ```
71
93
 
72
94
  ### 4) npm 公開
@@ -80,14 +102,15 @@ npm publish
80
102
  `npx ae-agent-skills install` は latest release の `.zxp` を参照するため、Release に ZXP を添付します。
81
103
 
82
104
  ```bash
83
- gh release create v0.2.7 dist/ae-agent-skill-0.2.7.zxp \
84
- --title v0.2.7 \
105
+ gh release create v0.3.0 dist/ae-agent-skill-0.3.0.zxp \
106
+ --title v0.3.0 \
85
107
  --notes "Release notes"
86
108
  ```
87
109
 
88
110
  ### 6) 公開後確認
89
111
 
90
112
  ```bash
113
+ npm --cache /private/tmp/ae-agent-npm-cache pack --dry-run
91
114
  npm view ae-agent-skills version dist-tags.latest --json
92
115
  gh release view --repo yumehiko/ae-agent-skills --json tagName,assets
93
116
  ```
@@ -22,7 +22,15 @@ Then fully quit and relaunch After Effects.
22
22
 
23
23
  ```bash
24
24
  python3 -m pip install -e ".[dev]"
25
- PYTHONPATH=src pytest
25
+ PYTHONPATH=src python3 -m pytest
26
+ npm run test:node
27
+ ```
28
+
29
+ `package.json`, `pyproject.toml`, and `CSXS/manifest.xml` versions should stay aligned for releases.
30
+ Before publishing, run:
31
+
32
+ ```bash
33
+ npm --cache /private/tmp/ae-agent-npm-cache pack --dry-run
26
34
  ```
27
35
 
28
36
  ## Project structure
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ae-agent-skills",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "One-command installer for the ae-agent-skill After Effects extension and CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,9 @@
8
8
  "ae-agent-setup": "bin/ae-agent-setup.mjs"
9
9
  },
10
10
  "scripts": {
11
+ "build:zxp": "./scripts/signing/build-zxp-interactive.sh",
11
12
  "sync:version": "node scripts/release/sync-version.mjs",
13
+ "test:node": "node --test tests/*.test.mjs",
12
14
  "version": "npm run sync:version"
13
15
  },
14
16
  "files": [
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Build signed ZXP by prompting for certificate password interactively.
5
+ # Optional env:
6
+ # SIGN_CERT_P12=certs/dev-cert.p12
7
+ # ZXPSIGNCMD_BIN=/absolute/path/to/ZXPSignCmd
8
+ # TIMESTAMP_URL=http://timestamp.digicert.com
9
+
10
+ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
11
+ CERT_P12="${SIGN_CERT_P12:-${ROOT_DIR}/certs/dev-cert.p12}"
12
+
13
+ if [[ ! -f "${CERT_P12}" ]]; then
14
+ echo "Certificate file not found: ${CERT_P12}" >&2
15
+ echo "Set SIGN_CERT_P12 to a valid .p12 file path." >&2
16
+ exit 1
17
+ fi
18
+
19
+ read -r -s -p "SIGN_CERT_PASSWORD: " SIGN_CERT_PASSWORD
20
+ echo
21
+
22
+ if [[ -z "${SIGN_CERT_PASSWORD}" ]]; then
23
+ echo "Password is empty." >&2
24
+ exit 1
25
+ fi
26
+
27
+ SIGN_CERT_P12="${CERT_P12}" SIGN_CERT_PASSWORD="${SIGN_CERT_PASSWORD}" \
28
+ "${ROOT_DIR}/scripts/signing/build-zxp.sh"
29
+
30
+ unset SIGN_CERT_PASSWORD
@@ -0,0 +1,7 @@
1
+ Use the `aftereffects-cli` skill for this request.
2
+
3
+ Prefer direct `ae-cli` commands for surgical edits, inspection, property updates, expression debugging, and small changes to existing human-made After Effects scenes.
4
+
5
+ User request:
6
+
7
+ $ARGUMENTS
@@ -0,0 +1,7 @@
1
+ Use the `aftereffects-declarative` skill for this request.
2
+
3
+ Follow the skill workflow: check `ae-cli health`, create or update scene JSON under `~/ae-agent-skills/work/`, validate with `ae-cli apply-scene --validate-only`, apply it, inspect the result, and keep the completed scene JSON under `~/ae-agent-skills/done/`.
4
+
5
+ User request:
6
+
7
+ $ARGUMENTS
@@ -1,9 +1,9 @@
1
1
  ---
2
- name: aftereffects-cli-legacy
2
+ name: aftereffects-cli
3
3
  description: Command-by-command After Effects editing via ae-cli. Best for surgical edits on existing human-made scenes (especially partial expression/property changes) and for debugging.
4
4
  ---
5
5
 
6
- # aftereffects-cli-legacy
6
+ # aftereffects-cli
7
7
 
8
8
  低レベル CLI 操作(命令型)のスキル。
9
9
  新規構築の主軸は宣言型 `aftereffects-declarative` だが、**既存シーンへの外科的編集ではこのスキルを第一選択**にする。
@@ -81,7 +81,7 @@ description: Command-by-command After Effects editing via ae-cli. Best for surgi
81
81
  ae-cli health
82
82
  ae-cli create-comp --name "Skill_CLI_Minimal_Test" --width 1280 --height 720 --duration 3 --frame-rate 30
83
83
  ae-cli set-active-comp --comp-name "Skill_CLI_Minimal_Test"
84
- ae-cli add-layer --type text --name "Hello" --text "CLI skill test"
84
+ ae-cli add-layer --layer-type text --name "Hello" --text "CLI skill test"
85
85
  ae-cli layers
86
86
  ```
87
87
 
@@ -20,7 +20,7 @@ After Effects を宣言型 JSON で構築する標準スキル。
20
20
  - 新規 comp / 新規レイヤー群を組み上げる
21
21
  - 同種変更を複数箇所へ展開する
22
22
  - scene JSON を成果物として残し、再実行可能にしたい
23
- - 命令型(`aftereffects-cli-legacy`)を使う:
23
+ - 命令型(`aftereffects-cli`)を使う:
24
24
  - 人間が作った既存シーン(scene JSON 未管理)へ部分修正を入れる
25
25
  - 複雑な既存レイヤーに expression をピンポイント適用する
26
26
  - comp 全体の再宣言を避け、局所的に安全修正したい
@@ -152,4 +152,4 @@ ae-cli apply-scene --scene-file ~/ae-agent-skills/work/min.scene.json
152
152
  - 旧レイヤーが残る:
153
153
  - `apply-scene --mode replace-managed` または `--mode clear-all` を使う
154
154
  - 既存シーンへ局所修正したい / 宣言型で表現しづらい:
155
- - `aftereffects-cli-legacy` へ切り替え
155
+ - `aftereffects-cli` へ切り替え