autokap 1.0.10 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/skill/OPCODE-REFERENCE.md +1 -41
- package/assets/skill/README.md +0 -1
- package/assets/skill/SKILL.md +9 -32
- package/assets/skill/references/examples.md +1 -17
- package/dist/billing-operation-logging.d.ts +2 -5
- package/dist/billing-operation-logging.js +0 -7
- package/dist/capture-strategy.d.ts +2 -8
- package/dist/capture-strategy.js +2 -30
- package/dist/cli-config.d.ts +2 -1
- package/dist/cli-config.js +18 -2
- package/dist/cli-contract.d.ts +1 -0
- package/dist/cli-contract.js +8 -2
- package/dist/cli-runner-local.d.ts +2 -0
- package/dist/cli-runner-local.js +12 -21
- package/dist/cli-runner.d.ts +4 -0
- package/dist/cli-runner.js +30 -50
- package/dist/cli.js +89 -44
- package/dist/cost-logging.d.ts +1 -1
- package/dist/execution-schema.d.ts +143 -331
- package/dist/execution-schema.js +43 -28
- package/dist/execution-types.d.ts +6 -151
- package/dist/execution-types.js +1 -3
- package/dist/logger.js +1 -1
- package/dist/mockup-html.d.ts +2 -0
- package/dist/mockup-html.js +13 -10
- package/dist/mockup.js +2 -2
- package/dist/opcode-actions.js +0 -2
- package/dist/opcode-runner.js +0 -121
- package/dist/program-signing.d.ts +50 -72
- package/dist/security.js +2 -2
- package/dist/server-capture-runtime.d.ts +0 -1
- package/dist/server-capture-runtime.js +0 -3
- package/dist/server-credit-usage.d.ts +1 -1
- package/dist/skill-packaging.d.ts +1 -1
- package/dist/skill-packaging.js +1 -11
- package/dist/types.d.ts +2 -2
- package/dist/web-playwright-local.d.ts +0 -14
- package/dist/web-playwright-local.js +0 -194
- package/package.json +1 -18
- package/readme.md +13 -0
- package/assets/skill/STUDIO-SKILL.md +0 -476
- package/assets/skill/references/interactive-demo.md +0 -225
package/dist/cli-runner.js
CHANGED
|
@@ -46,7 +46,7 @@ export async function runCapture(options) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
else {
|
|
49
|
-
const fetched = await fetchProgram(config, options.presetId);
|
|
49
|
+
const fetched = await fetchProgram(config, options.presetId, options.env);
|
|
50
50
|
if (!fetched.success) {
|
|
51
51
|
return { success: false, error: fetched.error };
|
|
52
52
|
}
|
|
@@ -151,15 +151,29 @@ export async function runCapture(options) {
|
|
|
151
151
|
logger.info(`[capture] Captures saved successfully — total ${totalDurationSec}s`);
|
|
152
152
|
}
|
|
153
153
|
catch (err) {
|
|
154
|
-
|
|
154
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
155
|
+
logger.error(`[capture] Failed to upload results: ${message}`);
|
|
156
|
+
if (!options.allowUploadFailure) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
runResult,
|
|
160
|
+
error: runResult.success
|
|
161
|
+
? `upload failed: ${message}`
|
|
162
|
+
: `${runResult.error ?? 'capture failed'}; upload failed: ${message}`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
logger.warn('[capture] Continuing after upload failure because --allow-upload-failure was set');
|
|
155
166
|
}
|
|
156
167
|
return { success: runResult.success, runResult };
|
|
157
168
|
}
|
|
158
169
|
// ── Server communication ────────────────────────────────────────────
|
|
159
|
-
async function fetchProgram(config, presetId) {
|
|
170
|
+
async function fetchProgram(config, presetId, environmentName) {
|
|
160
171
|
try {
|
|
161
|
-
const url = `${config.apiBaseUrl}/api/cli/programs/${presetId}
|
|
162
|
-
|
|
172
|
+
const url = new URL(`${config.apiBaseUrl}/api/cli/programs/${presetId}`);
|
|
173
|
+
if (environmentName) {
|
|
174
|
+
url.searchParams.set('env', environmentName);
|
|
175
|
+
}
|
|
176
|
+
const response = await fetch(url.toString(), {
|
|
163
177
|
headers: {
|
|
164
178
|
'Authorization': `Bearer ${config.apiKey}`,
|
|
165
179
|
'Content-Type': 'application/json',
|
|
@@ -167,7 +181,7 @@ async function fetchProgram(config, presetId) {
|
|
|
167
181
|
},
|
|
168
182
|
});
|
|
169
183
|
if (!response.ok) {
|
|
170
|
-
return { success: false, error: await formatServerError(response, url) };
|
|
184
|
+
return { success: false, error: await formatServerError(response, url.toString()) };
|
|
171
185
|
}
|
|
172
186
|
const data = await response.json();
|
|
173
187
|
const envelope = verifySignedExecutionProgramEnvelope({
|
|
@@ -195,7 +209,7 @@ async function uploadResults(config, program, result) {
|
|
|
195
209
|
const formData = new FormData();
|
|
196
210
|
const filename = buildArtifactFilename(program.presetId, variant.variantId, artifact);
|
|
197
211
|
uploadedCount += 1;
|
|
198
|
-
const label = artifact.captureName ?? artifact.clipName ??
|
|
212
|
+
const label = artifact.captureName ?? artifact.clipName ?? filename;
|
|
199
213
|
logger.info(`[capture] Exporting capture ${uploadedCount}/${totalArtifacts}: ${label}`);
|
|
200
214
|
formData.append('file', new Blob([new Uint8Array(artifact.buffer)], { type: artifact.mimeType }), filename);
|
|
201
215
|
formData.append('presetId', program.presetId);
|
|
@@ -253,35 +267,6 @@ async function uploadResults(config, program, result) {
|
|
|
253
267
|
if (typeof artifact.trimStartMs === 'number') {
|
|
254
268
|
formData.append('trimStartMs', String(artifact.trimStartMs));
|
|
255
269
|
}
|
|
256
|
-
// ── Interactive demo (mediaMode === 'dom') ──
|
|
257
|
-
if (artifact.stateName) {
|
|
258
|
-
formData.append('stateName', artifact.stateName);
|
|
259
|
-
}
|
|
260
|
-
if (artifact.domAssetUrls && artifact.domAssetUrls.length > 0) {
|
|
261
|
-
formData.append('domAssetUrls', JSON.stringify(artifact.domAssetUrls));
|
|
262
|
-
}
|
|
263
|
-
if (artifact.domThumbnailBuffer) {
|
|
264
|
-
formData.append('domThumbnail', new Blob([new Uint8Array(artifact.domThumbnailBuffer)], { type: 'image/png' }), 'thumbnail.png');
|
|
265
|
-
}
|
|
266
|
-
// Phase 5: fragment fields
|
|
267
|
-
if (artifact.fragmentName) {
|
|
268
|
-
formData.append('fragmentName', artifact.fragmentName);
|
|
269
|
-
}
|
|
270
|
-
// Phase 8: variant of the fragment capture (defaults to 'default'
|
|
271
|
-
// server-side when omitted, but we always send it explicitly so the
|
|
272
|
-
// upload row's unique key includes it).
|
|
273
|
-
if (artifact.fragmentVariantName) {
|
|
274
|
-
formData.append('fragmentVariantName', artifact.fragmentVariantName);
|
|
275
|
-
}
|
|
276
|
-
if (artifact.parentStateName) {
|
|
277
|
-
formData.append('parentStateName', artifact.parentStateName);
|
|
278
|
-
}
|
|
279
|
-
if (artifact.mountStrategy) {
|
|
280
|
-
formData.append('mountStrategy', artifact.mountStrategy);
|
|
281
|
-
}
|
|
282
|
-
if (artifact.mountTargetSelector) {
|
|
283
|
-
formData.append('mountTargetSelector', artifact.mountTargetSelector);
|
|
284
|
-
}
|
|
285
270
|
const response = await fetch(`${config.apiBaseUrl}/api/cli/artifacts`, {
|
|
286
271
|
method: 'POST',
|
|
287
272
|
headers: { 'Authorization': `Bearer ${config.apiKey}` },
|
|
@@ -438,17 +423,15 @@ function createHealerLLMProvider(llmConfig) {
|
|
|
438
423
|
};
|
|
439
424
|
}
|
|
440
425
|
function buildArtifactFilename(presetId, variantId, artifact) {
|
|
441
|
-
const ext = artifact.
|
|
442
|
-
? '
|
|
443
|
-
: artifact.mimeType === 'image/
|
|
444
|
-
? '
|
|
445
|
-
: artifact.mimeType
|
|
446
|
-
? '
|
|
447
|
-
: artifact.mimeType.includes('
|
|
448
|
-
? '
|
|
449
|
-
:
|
|
450
|
-
? 'mp4'
|
|
451
|
-
: 'webm';
|
|
426
|
+
const ext = artifact.mimeType === 'image/jpeg'
|
|
427
|
+
? 'jpg'
|
|
428
|
+
: artifact.mimeType === 'image/png'
|
|
429
|
+
? 'png'
|
|
430
|
+
: artifact.mimeType.includes('gif')
|
|
431
|
+
? 'gif'
|
|
432
|
+
: artifact.mimeType.includes('mp4')
|
|
433
|
+
? 'mp4'
|
|
434
|
+
: 'webm';
|
|
452
435
|
const stepToken = typeof artifact.stepIndex === 'number' ? `-${artifact.stepIndex}` : '';
|
|
453
436
|
return `${sanitizeArtifactToken(presetId)}-${sanitizeArtifactToken(variantId)}${stepToken}.${ext}`;
|
|
454
437
|
}
|
|
@@ -497,9 +480,6 @@ function sanitizeArtifactForTelemetry(artifact) {
|
|
|
497
480
|
altText: redactTelemetryText(artifact.altText),
|
|
498
481
|
captureUrl: redactUrl(artifact.captureUrl),
|
|
499
482
|
elementSelector: undefined,
|
|
500
|
-
domAssetUrls: artifact.domAssetUrls
|
|
501
|
-
?.map((entry) => redactUrl(entry))
|
|
502
|
-
.filter((entry) => Boolean(entry)),
|
|
503
483
|
};
|
|
504
484
|
}
|
|
505
485
|
function sanitizeHealerPatches(patches) {
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import fs from 'node:fs/promises';
|
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
7
|
const { version } = require('../package.json');
|
|
8
8
|
import { logger } from './logger.js';
|
|
9
|
-
import { writeConfig, deleteConfig, requireConfig, getConfigPath, DEFAULT_API_BASE_URL, getDefaultApiBaseUrl, getDefaultWsUrl, LOCAL_API_BASE_URL, LOCAL_WS_URL, API_BASE_URL_ENV_VAR, WS_URL_ENV_VAR, } from './cli-config.js';
|
|
9
|
+
import { writeConfig, deleteConfig, requireConfig, getConfigPath, DEFAULT_API_BASE_URL, getDefaultApiBaseUrl, getDefaultWsUrl, LOCAL_API_BASE_URL, LOCAL_WS_URL, API_KEY_ENV_VAR, API_BASE_URL_ENV_VAR, WS_URL_ENV_VAR, } from './cli-config.js';
|
|
10
10
|
import { renderSkillSingleFile, writeSkillExport } from './skill-packaging.js';
|
|
11
11
|
// ── Program definition ──────────────────────────────────────────────
|
|
12
12
|
export const program = new Command();
|
|
@@ -14,6 +14,12 @@ program
|
|
|
14
14
|
.name('autokap')
|
|
15
15
|
.version(version)
|
|
16
16
|
.description('AI-powered screenshot capture — local Playwright proxy');
|
|
17
|
+
function getProjectPrimaryUrl(project) {
|
|
18
|
+
return (project.environments.local ??
|
|
19
|
+
project.environments.staging ??
|
|
20
|
+
project.environments.prod ??
|
|
21
|
+
null);
|
|
22
|
+
}
|
|
17
23
|
function fatal(message) {
|
|
18
24
|
logger.error(message);
|
|
19
25
|
process.exit(1);
|
|
@@ -205,6 +211,8 @@ program
|
|
|
205
211
|
.description('Run a capture using the deterministic opcode engine (local Playwright)')
|
|
206
212
|
.option('--headed', 'Show browser window for debugging', false)
|
|
207
213
|
.option('--local', `Use the local AutoKap dev server (${LOCAL_API_BASE_URL})`, false)
|
|
214
|
+
.option('--env <name>', "Project environment to capture against. Falls back to the project's default environment when omitted.")
|
|
215
|
+
.option('--allow-upload-failure', 'Keep a successful capture exit code even if artifact upload fails', false)
|
|
208
216
|
.option('--output <dir>', 'Optional output directory for local artifact copies')
|
|
209
217
|
.option('--program <file>', 'Path to a program JSON file')
|
|
210
218
|
.option('--debug', 'Verbose logging: per-substep timing, opcode dumps, recovery strategy traces', false)
|
|
@@ -222,6 +230,59 @@ program
|
|
|
222
230
|
const { runLocal } = await import('./cli-runner-local.js');
|
|
223
231
|
await runLocal(presetId, opts);
|
|
224
232
|
});
|
|
233
|
+
// ── auto-recapture command ─────────────────────────────────────────
|
|
234
|
+
program
|
|
235
|
+
.command('auto-recapture')
|
|
236
|
+
.description('Run every preset enabled for CI auto-recapture in a project')
|
|
237
|
+
.requiredOption('--project <id>', 'Project ID')
|
|
238
|
+
.option('--env <name>', "Project environment to capture against. Falls back to the project's default environment when omitted.")
|
|
239
|
+
.option('--headed', 'Show browser window for debugging', false)
|
|
240
|
+
.option('--local', `Use the local AutoKap dev server (${LOCAL_API_BASE_URL})`, false)
|
|
241
|
+
.option('--allow-upload-failure', 'Keep a successful capture exit code even if artifact upload fails', false)
|
|
242
|
+
.option('--debug', 'Verbose logging: per-substep timing, opcode dumps, recovery strategy traces', false)
|
|
243
|
+
.action(async (opts) => {
|
|
244
|
+
if (opts.debug) {
|
|
245
|
+
const { setDebugEnabled } = await import('./logger.js');
|
|
246
|
+
setDebugEnabled(true);
|
|
247
|
+
logger.info('[capture] Debug mode enabled — verbose logging on');
|
|
248
|
+
}
|
|
249
|
+
if (opts.local) {
|
|
250
|
+
process.env[API_BASE_URL_ENV_VAR] = LOCAL_API_BASE_URL;
|
|
251
|
+
process.env[WS_URL_ENV_VAR] = LOCAL_WS_URL;
|
|
252
|
+
logger.info(`Using local AutoKap dev server: ${LOCAL_API_BASE_URL}`);
|
|
253
|
+
}
|
|
254
|
+
const config = await requireConfig();
|
|
255
|
+
const data = await requestJson(config, `/api/cli/projects/${opts.project}/auto-recapture-presets`, { headers: authHeaders(config) }, 'Failed to list auto-recapture presets');
|
|
256
|
+
if (data.presets.length === 0) {
|
|
257
|
+
logger.info(`[auto-recapture] No presets enabled for project ${opts.project}`);
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}
|
|
260
|
+
const { runCapture } = await import('./cli-runner.js');
|
|
261
|
+
const failures = [];
|
|
262
|
+
for (const preset of data.presets) {
|
|
263
|
+
const label = preset.name ? `${preset.name} (${preset.id})` : preset.id;
|
|
264
|
+
logger.info(`[auto-recapture] Running ${label}`);
|
|
265
|
+
const result = await runCapture({
|
|
266
|
+
presetId: preset.id,
|
|
267
|
+
env: opts.env,
|
|
268
|
+
headed: opts.headed,
|
|
269
|
+
allowUploadFailure: opts.allowUploadFailure,
|
|
270
|
+
});
|
|
271
|
+
if (!result.success) {
|
|
272
|
+
const error = result.error ?? result.runResult?.error ?? 'capture failed';
|
|
273
|
+
failures.push({ id: preset.id, name: preset.name, error });
|
|
274
|
+
logger.error(`[auto-recapture] Failed ${label}: ${error}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (failures.length > 0) {
|
|
278
|
+
logger.error(`[auto-recapture] ${failures.length}/${data.presets.length} preset(s) failed: ${failures
|
|
279
|
+
.map((failure) => failure.name ?? failure.id)
|
|
280
|
+
.join(', ')}`);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
logger.success(`[auto-recapture] ${data.presets.length} preset(s) recaptured successfully`);
|
|
284
|
+
process.exit(0);
|
|
285
|
+
});
|
|
225
286
|
// ── project commands ───────────────────────────────────────────────
|
|
226
287
|
const projectCmd = program
|
|
227
288
|
.command('project')
|
|
@@ -248,16 +309,23 @@ projectCmd
|
|
|
248
309
|
.command('create')
|
|
249
310
|
.description('Create a project')
|
|
250
311
|
.requiredOption('--name <name>', 'Project name')
|
|
251
|
-
.requiredOption('--url <url>', '
|
|
312
|
+
.requiredOption('--base-url <url>', 'Base URL of the chosen environment')
|
|
313
|
+
.option('--environment <name>', "Environment slot to seed: 'local' or 'prod'", 'local')
|
|
252
314
|
.option('--description <text>', 'Project description')
|
|
253
315
|
.action(async (opts) => {
|
|
254
316
|
const config = await requireConfig();
|
|
317
|
+
const env = opts.environment.toLowerCase();
|
|
318
|
+
if (env !== 'local' && env !== 'prod') {
|
|
319
|
+
logger.error("--environment must be 'local' or 'prod'");
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
255
322
|
const data = await requestJson(config, '/api/v1/projects', {
|
|
256
323
|
method: 'POST',
|
|
257
324
|
headers: authHeaders(config, { 'Content-Type': 'application/json' }),
|
|
258
325
|
body: JSON.stringify({
|
|
259
326
|
name: opts.name,
|
|
260
|
-
|
|
327
|
+
environment: env,
|
|
328
|
+
base_url: opts.baseUrl,
|
|
261
329
|
description: opts.description,
|
|
262
330
|
}),
|
|
263
331
|
}, 'Failed to create project');
|
|
@@ -492,19 +560,9 @@ presetCmd
|
|
|
492
560
|
// Build per-endpoint info with type-specific URL params
|
|
493
561
|
const endpointEntries = endpoints.map((ep) => {
|
|
494
562
|
const assetType = ep.asset_type ?? 'screenshot';
|
|
495
|
-
const url =
|
|
496
|
-
? `${cfg.apiBaseUrl}/demo/${presetId}`
|
|
497
|
-
: `${cfg.apiBaseUrl}/api/v1/assets/${ep.id}`;
|
|
563
|
+
const url = `${cfg.apiBaseUrl}/api/v1/assets/${ep.id}`;
|
|
498
564
|
let urlParams;
|
|
499
|
-
if (assetType === '
|
|
500
|
-
urlParams = {
|
|
501
|
-
embed: 'Set to "1" for iframe embedding',
|
|
502
|
-
lang: 'Language variant',
|
|
503
|
-
theme: 'Color theme ("light" or "dark")',
|
|
504
|
-
target: 'Device target ID',
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
else if (assetType === 'screenshot') {
|
|
565
|
+
if (assetType === 'screenshot') {
|
|
508
566
|
urlParams = {
|
|
509
567
|
lang: 'Language variant',
|
|
510
568
|
theme: 'Color theme ("light" or "dark")',
|
|
@@ -513,8 +571,6 @@ presetCmd
|
|
|
513
571
|
quality: 'Image quality 1-100',
|
|
514
572
|
format: 'Output format: "webp", "png", "jpg"',
|
|
515
573
|
scale: 'Resolution multiplier (0.5-4)',
|
|
516
|
-
render: 'Set to "studio" for Studio render',
|
|
517
|
-
slot: 'Studio composition slot',
|
|
518
574
|
};
|
|
519
575
|
}
|
|
520
576
|
else if (assetType === 'clip') {
|
|
@@ -523,14 +579,6 @@ presetCmd
|
|
|
523
579
|
theme: 'Color theme ("light" or "dark")',
|
|
524
580
|
target: 'Device target ID',
|
|
525
581
|
format: 'Output format: "gif" (default), "mp4"',
|
|
526
|
-
render: 'Set to "studio" for Studio render',
|
|
527
|
-
slot: 'Studio composition slot',
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
else if (assetType === 'composition') {
|
|
531
|
-
urlParams = {
|
|
532
|
-
scale: 'Resolution multiplier (0.5-4)',
|
|
533
|
-
format: 'Output format: "png", "webp", "jpg"',
|
|
534
582
|
};
|
|
535
583
|
}
|
|
536
584
|
else {
|
|
@@ -555,12 +603,6 @@ presetCmd
|
|
|
555
603
|
variants: { langs, themes, targets },
|
|
556
604
|
endpoints: endpointEntries,
|
|
557
605
|
};
|
|
558
|
-
if (captureMode === 'interactive_demo') {
|
|
559
|
-
info.interactive_demo = {
|
|
560
|
-
url: `${cfg.apiBaseUrl}/demo/${presetId}`,
|
|
561
|
-
embed_url: `${cfg.apiBaseUrl}/demo/${presetId}?embed=1`,
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
606
|
console.log(JSON.stringify(info, null, 2));
|
|
565
607
|
process.exit(0);
|
|
566
608
|
});
|
|
@@ -617,7 +659,15 @@ authCmd
|
|
|
617
659
|
}
|
|
618
660
|
process.exit(0);
|
|
619
661
|
}
|
|
620
|
-
|
|
662
|
+
let startUrl = opts.url;
|
|
663
|
+
if (!startUrl) {
|
|
664
|
+
const project = await loadProject(cfg, projectId);
|
|
665
|
+
startUrl = getProjectPrimaryUrl(project) ?? undefined;
|
|
666
|
+
}
|
|
667
|
+
if (!startUrl) {
|
|
668
|
+
logger.error(`No environment URL configured for project ${projectId}. Configure local/staging/prod in the AutoKap web UI, or pass --url.`);
|
|
669
|
+
process.exit(1);
|
|
670
|
+
}
|
|
621
671
|
logger.info(`Opening ${startUrl}`);
|
|
622
672
|
const { captureAuthSession } = await import('./auth-capture.js');
|
|
623
673
|
await captureAuthSession({
|
|
@@ -840,25 +890,16 @@ const AGENT_PATHS = {
|
|
|
840
890
|
windsurf: '.windsurf/rules/autokap-preset.md',
|
|
841
891
|
copilot: '.github/instructions/autokap-preset.instructions.md',
|
|
842
892
|
};
|
|
843
|
-
const STUDIO_AGENT_PATHS = {
|
|
844
|
-
claude: '.claude/commands/autokap-studio.md',
|
|
845
|
-
codex: '.agents/skills/autokap-studio/SKILL.md',
|
|
846
|
-
cursor: '.cursor/rules/autokap-studio.md',
|
|
847
|
-
windsurf: '.windsurf/rules/autokap-studio.md',
|
|
848
|
-
copilot: '.github/instructions/autokap-studio.instructions.md',
|
|
849
|
-
};
|
|
850
893
|
program
|
|
851
894
|
.command('skill')
|
|
852
895
|
.description('Output or install an AutoKap skill for AI coding agents')
|
|
853
896
|
.option('--output <path>', 'Write the generated skill output to this path instead of stdout')
|
|
854
897
|
.option('--agent <name>', 'Target AI coding agent: claude, codex, cursor, windsurf, copilot (auto-resolves output path and packaging mode)')
|
|
855
|
-
.option('--type <type>', 'Skill type: preset (default) or studio (composition designer)')
|
|
856
898
|
.option('--project-url <url>', 'Replace the project URL placeholder in the skill')
|
|
857
899
|
.option('--project-id <id>', 'Replace the project ID placeholder in the skill')
|
|
858
900
|
.option('--api-base-url <url>', 'Replace the API base URL placeholder (default: https://autokap.app)')
|
|
859
901
|
.action(async (opts) => {
|
|
860
|
-
const
|
|
861
|
-
const pathMap = skillType === 'studio' ? STUDIO_AGENT_PATHS : AGENT_PATHS;
|
|
902
|
+
const pathMap = AGENT_PATHS;
|
|
862
903
|
// Resolve --agent to an output path
|
|
863
904
|
if (opts.agent) {
|
|
864
905
|
const agentKey = opts.agent.toLowerCase();
|
|
@@ -875,7 +916,7 @@ program
|
|
|
875
916
|
try {
|
|
876
917
|
if (opts.output) {
|
|
877
918
|
const result = await writeSkillExport({
|
|
878
|
-
type:
|
|
919
|
+
type: 'preset',
|
|
879
920
|
agent: opts.agent?.toLowerCase(),
|
|
880
921
|
outputPath: opts.output,
|
|
881
922
|
placeholders: opts,
|
|
@@ -889,7 +930,7 @@ program
|
|
|
889
930
|
}
|
|
890
931
|
else {
|
|
891
932
|
const content = await renderSkillSingleFile({
|
|
892
|
-
type:
|
|
933
|
+
type: 'preset',
|
|
893
934
|
agent: opts.agent?.toLowerCase(),
|
|
894
935
|
placeholders: opts,
|
|
895
936
|
});
|
|
@@ -916,6 +957,10 @@ program
|
|
|
916
957
|
// If --cli-key not provided, prompt interactively
|
|
917
958
|
let cliKey = opts.cliKey;
|
|
918
959
|
if (!cliKey) {
|
|
960
|
+
if (process.stdin.isTTY === false) {
|
|
961
|
+
logger.error(`CLI key is required in non-interactive shells. Pass --cli-key <key> or set ${API_KEY_ENV_VAR} for CI runs.`);
|
|
962
|
+
process.exit(1);
|
|
963
|
+
}
|
|
919
964
|
const readline = await import('node:readline');
|
|
920
965
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
921
966
|
cliKey = await new Promise((resolve) => {
|
package/dist/cost-logging.d.ts
CHANGED