@promptframe/cli 0.1.66 → 0.1.68
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/README.md +32 -1
- package/dist/configuration.d.ts +13 -0
- package/dist/configuration.d.ts.map +1 -0
- package/dist/configuration.js +36 -0
- package/dist/configuration.js.map +1 -0
- package/dist/index.js +94 -25
- package/dist/index.js.map +1 -1
- package/dist/preview-resource-draft.d.ts +31 -0
- package/dist/preview-resource-draft.d.ts.map +1 -0
- package/dist/preview-resource-draft.js +185 -0
- package/dist/preview-resource-draft.js.map +1 -0
- package/dist/preview-resource-server.d.ts +23 -0
- package/dist/preview-resource-server.d.ts.map +1 -0
- package/dist/preview-resource-server.js +278 -0
- package/dist/preview-resource-server.js.map +1 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ PromptFrame component authoring CLI.
|
|
|
8
8
|
|
|
9
9
|
Use it to inspect the public component standard, check component folders, validate manifests, inspect the local preview envelope, package source archives, upload components, check build status, rebuild evidence indexes, and rerun layout/security probes.
|
|
10
10
|
|
|
11
|
-
Current source baseline is `@promptframe/cli@0.1.
|
|
11
|
+
Current source baseline is `@promptframe/cli@0.1.68`, `@promptframe/contracts@0.1.36`, `@promptframe/component-kit@0.1.30`, and `create-promptframe-component@0.1.58`. The published CLI consumes the contracts AST-aware public security policy evaluator, reports `securityPolicyDigest` / `securityEvaluatorMode` in JSON output, rejects red-team browser capability vectors such as Image/Audio beacons, Worker/SharedWorker, `window.open`, `postMessage`, dynamic script/iframe creation, browser fingerprinting, storage/cookie access, and dangerous HTML, reports `publicResources` for component-level public assets, keeps native `<img>` / `<video>` source checks case-sensitive so Remotion `<Img>` / `<Video>` remain valid, validates preview props against statically declared `propsSchema` fields and requires readable public prop descriptions, enforces strict Slot-first layout/source diagnostics, supports endpoint discovery, project list/current diagnostics, self-service CI token create/list/revoke, single-component and workspace GitHub workflow setup with `promptframe-workflow-version: 2`, `setup-ci --upgrade` stale-template repair, dynamic workspace matrix discovery, `RUNNER_LABELS` and pnpm 10 workflow support, pnpm workspace root lockfile evidence without component symlinks, `promptframe-workspace.json` validation, workspace root `check .` / `upload .` auto-detection, explicit `workspace:*` shared-package diagnostics, workspace upload source metadata headers, packages sanitized lockfile evidence for platform admission, release notes forwarding to upload, stderr NDJSON upload progress for `--json`, human-readable token kind/expiry summaries for `login`, `whoami`, and authenticated `upload`, server version auto-bump notes, and supports `status --fail-on-build-failed` for CI build-status gating.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm install -D @promptframe/cli
|
|
@@ -206,3 +206,34 @@ promptframe dev stop .
|
|
|
206
206
|
关闭开发面板不停止连接;切换账号或作品、关闭页面会断开。刷新页面后重新粘贴连接JSON。停止或替换仅操作本工作区的实际实例;无法确认实例退出时命令报错,不自动强制终止进程。
|
|
207
207
|
|
|
208
208
|
上传组件后,用准确的正式 `componentRef` 替换作品节点引用并移除该节点的 `componentSource`。仅上传成功不会自动改变作品的选源。确认作品已使用正式引用且不再需要本地预览后,可执行 `promptframe dev stop .`。
|
|
209
|
+
|
|
210
|
+
## 素材引用槽与本地私有预览
|
|
211
|
+
|
|
212
|
+
在 schema 中用 `promptFrameResourceSchema` 声明素材参数,在组件中用 `promptFrameResource` 消费。参数保存 public 路径或 `asset-proxy://` 引用;组件不读取凭据,也不调用平台解析接口。
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { z } from 'zod';
|
|
216
|
+
import { promptFrameResourceSchema } from '@promptframe/contracts';
|
|
217
|
+
export const propsSchema = z.object({
|
|
218
|
+
illustration: promptFrameResourceSchema({
|
|
219
|
+
kinds: ['image'], sources: ['public', 'asset'],
|
|
220
|
+
accept: ['image/png', 'image/jpeg'], maxFileBytes: 16 * 1024 * 1024,
|
|
221
|
+
}).describe('展示图片').default('/example.png'),
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
组件使用 `<Img src={promptFrameResource(props, props.illustration)} />`。本地、Studio 预览和正式渲染使用同一写法;解析由宿主完成。正式渲染缺失、错误类型或越权引用会报错,不自动替换作品内容。
|
|
226
|
+
|
|
227
|
+
新模板已启用 Vite 适配器。自定义旧项目在 `vite.config.ts` 的 plugins 中加入 `promptFramePreviewResources()`(从 `@promptframe/cli/preview` 导入),再运行 `promptframe sync . --apply` 更新预览壳;已有 React 插件等设置继续保留。适配器仅在本机 loopback 开发服务中运行,不导入组件业务代码。
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
promptframe resource set . --prop /illustration --file ./my-selected.png
|
|
231
|
+
promptframe resource status .
|
|
232
|
+
promptframe resource clear .
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
本人明确选择的 PNG、JPEG、WebP 文件最大 16MiB,并受槽声明的 MIME/大小限制。CLI 记录原文件身份和 SHA,不复制原件;每次读取重新核对。选择存入 ignored 的 `.promptframe/local-previews/resources.json`,不会改公开 `preview-props.json`,打包固定排除此目录。选择最多 16 项,24 小时后不再提供读取;`resource clear` 只移除受管选择记录,不删除原始文件。没有后台清理进程。
|
|
236
|
+
|
|
237
|
+
平台素材使用同一选择命令的 `--asset-ref` 和原作品 `--session-id`,不得与 `--file` 同用。项目来自正常 `promptframe init` 写入的无凭据上下文。需要先沿正常 `promptframe login --endpoint <平台API> --with-assets` 授予 `asset.read`;旧组件上传凭据不会自动扩大权限。开发服务复用现有 CLI 凭据,逐次请求当前用户、项目与作品范围内的短时只读表示,核字节 SHA 后向浏览器提供本机地址。凭据、签名 URL 和私有文件路径不会发送给组件。断网、撤权、文件变化或选择过期时,预览明确提示不可用并标明正在展示包内示例;恢复条件后刷新。
|
|
238
|
+
|
|
239
|
+
市场预览的素材选择读取访问者当前作品中的就绪素材,不改变组件包或上传新素材。正式使用时将合法素材引用冻结在 Spec,渲染入口沿原授权、素材存储和预下载合同准备本地表示;签名 URL 不保存到 Spec。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class CliCredentialError extends Error {
|
|
2
|
+
readonly code: 'cli.auth.token_expired';
|
|
3
|
+
constructor(code: 'cli.auth.token_expired');
|
|
4
|
+
}
|
|
5
|
+
export declare function readCliConfiguration(path: string): Record<string, unknown>;
|
|
6
|
+
/** Shared read-only access to the existing credential; never logs or writes it. */
|
|
7
|
+
export declare function cliBearerToken(input: {
|
|
8
|
+
endpoint: string;
|
|
9
|
+
explicit?: string;
|
|
10
|
+
configuration: Record<string, unknown>;
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}): string | undefined;
|
|
13
|
+
//# sourceMappingURL=configuration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"AAEA,qBAAa,kBAAmB,SAAQ,KAAK;IAC/B,QAAQ,CAAC,IAAI,EAAE,wBAAwB;gBAA9B,IAAI,EAAE,wBAAwB;CACpD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM1E;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACjG,GAAG,MAAM,GAAG,SAAS,CAWrB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
export class CliCredentialError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code) {
|
|
5
|
+
super(code);
|
|
6
|
+
this.code = code;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function readCliConfiguration(path) {
|
|
10
|
+
if (!existsSync(path))
|
|
11
|
+
return {};
|
|
12
|
+
try {
|
|
13
|
+
const value = JSON.parse(readFileSync(path, 'utf8'));
|
|
14
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Shared read-only access to the existing credential; never logs or writes it. */
|
|
21
|
+
export function cliBearerToken(input) {
|
|
22
|
+
if (input.explicit)
|
|
23
|
+
return input.explicit;
|
|
24
|
+
const credential = input.configuration.credential;
|
|
25
|
+
if (!credential || typeof credential !== 'object' || Array.isArray(credential))
|
|
26
|
+
return undefined;
|
|
27
|
+
const row = credential;
|
|
28
|
+
const normalize = (value) => value.replace(/\/+$/, '');
|
|
29
|
+
if (typeof row.endpoint !== 'string' || normalize(row.endpoint) !== normalize(input.endpoint))
|
|
30
|
+
return undefined;
|
|
31
|
+
if (typeof row.expiresAt === 'string' && Date.parse(row.expiresAt) <= (input.now ?? Date.now)()) {
|
|
32
|
+
throw new CliCredentialError('cli.auth.token_expired');
|
|
33
|
+
}
|
|
34
|
+
return typeof row.tokenSecret === 'string' ? row.tokenSecret : undefined;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=configuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACtB;IAArB,YAAqB,IAA8B;QAAI,KAAK,CAAC,IAAI,CAAC,CAAC;QAA9C,SAAI,GAAJ,IAAI,CAA0B;IAAiB,CAAC;CACtE;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAgC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7G,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACxB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,KAE9B;IACC,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC,QAAQ,CAAC;IAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC;IAClD,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IACjG,MAAM,GAAG,GAAG,UAAqC,CAAC;IAClD,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAChH,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QAChG,MAAM,IAAI,kBAAkB,CAAC,wBAAwB,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,13 +6,15 @@ import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync,
|
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import { basename, dirname, extname, join, relative, resolve } from 'node:path';
|
|
8
8
|
import { inflateRawSync } from 'node:zlib';
|
|
9
|
+
import { cliBearerToken, readCliConfiguration } from './configuration.js';
|
|
9
10
|
import ignore from 'ignore';
|
|
10
|
-
import { COMPONENT_MANIFEST_SCHEMA_VERSION, COMPONENT_PUBLIC_RESOURCES_CONTRACT_VERSION, COMPONENT_REF_VERSION, COMPONENT_STANDARD_SOURCE_HASH, COMPONENT_STANDARD_VERSION, PROMPTFRAME_AUTHORING_STANDARD_RELEASE, PROMPTFRAME_PUBLIC_RESOURCE_LIMITS, PROMPTFRAME_PUBLIC_RESOURCE_POLICY, PROMPTFRAME_PUBLIC_SECURITY_POLICY, PROMPTFRAME_PUBLIC_SECURITY_POLICY_DIGEST, PROMPTFRAME_PUBLIC_STANDARD_POLICY, PROMPTFRAME_LAYOUT_POLICY_RULE_IDS, PROMPTFRAME_CONTRACTS_VERSION, PROMPTFRAME_PUBLIC_DEPENDENCY_POLICY, detectPromptFrameUnknownCustomStyleProps, evaluatePromptFrameLayoutPolicy, evaluatePromptFrameDependencyPolicy, authoringUploadTargetSchema, parseComponentManifest, } from '@promptframe/contracts';
|
|
11
|
+
import { COMPONENT_MANIFEST_SCHEMA_VERSION, COMPONENT_PUBLIC_RESOURCES_CONTRACT_VERSION, COMPONENT_REF_VERSION, COMPONENT_STANDARD_SOURCE_HASH, COMPONENT_STANDARD_VERSION, PROMPTFRAME_AUTHORING_STANDARD_RELEASE, PROMPTFRAME_PUBLIC_RESOURCE_LIMITS, PROMPTFRAME_PUBLIC_RESOURCE_POLICY, PROMPTFRAME_PUBLIC_SECURITY_POLICY, PROMPTFRAME_PUBLIC_SECURITY_POLICY_DIGEST, PROMPTFRAME_PUBLIC_STANDARD_POLICY, PROMPTFRAME_LAYOUT_POLICY_RULE_IDS, PROMPTFRAME_CONTRACTS_VERSION, PROMPTFRAME_PUBLIC_DEPENDENCY_POLICY, detectPromptFrameUnknownCustomStyleProps, evaluatePromptFrameLayoutPolicy, evaluatePromptFrameDependencyPolicy, collectPromptFrameResourceReferences, authoringUploadTargetSchema, parseComponentManifest, } from '@promptframe/contracts';
|
|
11
12
|
import { evaluatePromptFrameSecurityPolicySource, } from '@promptframe/contracts/security-evaluator';
|
|
12
13
|
import { evaluatePromptFrameSchemaSource, } from '@promptframe/contracts/schema-evaluator';
|
|
13
14
|
import { applyPackageChanges, buildFreshnessDecision, computePackageChanges, computePackageFreshnessDiagnostics, computeScaffoldFreshnessDiagnostics, resolveLocalPreviewScript, } from './lifecycle.js';
|
|
14
15
|
import { evaluateLocalReusability, reusabilityDiagnostics, } from './reusability.js';
|
|
15
16
|
import { assertPreviewEnvelope, writeLocalPreviewReport, } from './preview-report.js';
|
|
17
|
+
import { capturePreviewResourceFile, clearPreviewResourceDraft, previewResourcePropPath, readPreviewResourceDraft, writePreviewResourceSelection } from './preview-resource-draft.js';
|
|
16
18
|
const command = process.argv[2] ?? 'help';
|
|
17
19
|
const args = process.argv.slice(3);
|
|
18
20
|
const REQUIRED_COMPONENT_FILES = PROMPTFRAME_PUBLIC_STANDARD_POLICY.requiredFiles;
|
|
@@ -97,6 +99,9 @@ async function run(name, argv) {
|
|
|
97
99
|
case 'preview':
|
|
98
100
|
preview(argv);
|
|
99
101
|
break;
|
|
102
|
+
case 'resource':
|
|
103
|
+
resourceCommand(argv);
|
|
104
|
+
break;
|
|
100
105
|
case 'dev':
|
|
101
106
|
await dev(argv);
|
|
102
107
|
break;
|
|
@@ -384,7 +389,7 @@ function sync(argv) {
|
|
|
384
389
|
const nextFiles = [
|
|
385
390
|
{
|
|
386
391
|
path: GENERATED_PREVIEW_ROOT_PATH,
|
|
387
|
-
contents: renderPromptFrameThinPreviewRoot(),
|
|
392
|
+
contents: renderPromptFrameThinPreviewRoot(hasResourcePreviewAdapter(dir)),
|
|
388
393
|
},
|
|
389
394
|
{
|
|
390
395
|
path: DEV_PUBLIC_RESOURCES_MODULE_PATH,
|
|
@@ -542,6 +547,59 @@ async function dev(argv) {
|
|
|
542
547
|
return;
|
|
543
548
|
await runDevServer(dir, devCommand);
|
|
544
549
|
}
|
|
550
|
+
function resourceCommand(argv) {
|
|
551
|
+
const [action, directory] = positionalArgs(argv), root = resolve(directory ?? '.');
|
|
552
|
+
if (action === 'clear') {
|
|
553
|
+
clearPreviewResourceDraft(root);
|
|
554
|
+
printJson({ command: 'resource.clear', status: 'cleared', originalFilesDeleted: 0 });
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (action === 'status') {
|
|
558
|
+
const draft = readPreviewResourceDraft(root);
|
|
559
|
+
printJson({ command: 'resource.status', selectedCount: draft?.selections.length ?? 0,
|
|
560
|
+
updatedAt: draft?.updatedAt, credentialsIncluded: false });
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (action !== 'set')
|
|
564
|
+
fail('Use resource set|status|clear <component-directory>.', 'preview.resource.command_invalid', 2);
|
|
565
|
+
const prop = valueAfter(argv, '--prop'), file = valueAfter(argv, '--file'), reference = valueAfter(argv, '--asset-ref');
|
|
566
|
+
if (!prop || !!file === !!reference)
|
|
567
|
+
fail('Select --prop /field with exactly one --file or --asset-ref.', 'preview.resource.selection_invalid', 2);
|
|
568
|
+
const manifest = validateComponentDirectory(root), envelope = readPreviewProps(root);
|
|
569
|
+
const facts = evaluatePromptFrameSchemaSource(readFileSync(join(root, manifest.entry.propsSchemaPath), 'utf8'));
|
|
570
|
+
const props = structuredClone(envelope.props ?? {}), keys = previewResourcePropPath(prop);
|
|
571
|
+
let object = props;
|
|
572
|
+
for (const key of keys.slice(0, -1)) {
|
|
573
|
+
if (!object || typeof object !== 'object' || !Object.hasOwn(object, key))
|
|
574
|
+
fail('Resource field is missing.', 'preview.resource.prop_missing');
|
|
575
|
+
object = object[key];
|
|
576
|
+
}
|
|
577
|
+
if (!object || typeof object !== 'object')
|
|
578
|
+
fail('Resource field is missing.', 'preview.resource.prop_missing');
|
|
579
|
+
object[keys.at(-1)] = reference ?? '/local-preview.png';
|
|
580
|
+
const slot = collectPromptFrameResourceReferences({ type: 'object', properties: facts.properties }, props)
|
|
581
|
+
.find(row => JSON.stringify(row.path) === JSON.stringify(keys));
|
|
582
|
+
if (facts.status !== 'resolved' || !slot)
|
|
583
|
+
fail('Use promptFrameResourceSchema for this field.', 'preview.resource.slot_missing');
|
|
584
|
+
const selectedFile = file ? capturePreviewResourceFile(file) : undefined;
|
|
585
|
+
if (selectedFile && (!slot.slot.sources.includes('public') || !slot.slot.kinds.includes('image')
|
|
586
|
+
|| slot.slot.maxFileBytes !== undefined && selectedFile.size > slot.slot.maxFileBytes
|
|
587
|
+
|| slot.slot.accept?.length && !slot.slot.accept.some(type => type === '*/*' || type === selectedFile.contentType
|
|
588
|
+
|| type.endsWith('/*') && selectedFile.contentType.startsWith(type.slice(0, -1)))))
|
|
589
|
+
fail('Selected file does not match the declared slot.', 'preview.resource.file_rejected');
|
|
590
|
+
const sessionId = valueAfter(argv, '--session-id');
|
|
591
|
+
if (reference && !sessionId)
|
|
592
|
+
fail('A platform asset needs its original --session-id.', 'preview.resource.scope_required', 2);
|
|
593
|
+
const ignored = join(root, '.gitignore'), oldIgnore = existsSync(ignored) ? readFileSync(ignored, 'utf8') : '';
|
|
594
|
+
if (!ignore().add(oldIgnore).ignores('.promptframe/local-previews/resources.json'))
|
|
595
|
+
writeFileSync(ignored, oldIgnore.replace(/\n?$/, '\n') + '.promptframe/\n');
|
|
596
|
+
writePreviewResourceSelection(root, { prop, ...(selectedFile ? { file: selectedFile } : { reference, sessionId }) });
|
|
597
|
+
const config = existsSync(join(root, 'vite.config.ts')) ? readFileSync(join(root, 'vite.config.ts'), 'utf8') : '';
|
|
598
|
+
printJson({ command: 'resource.set', status: 'selected', prop, source: selectedFile ? 'local_file' : 'platform_asset',
|
|
599
|
+
draftOnly: true, sourcePreviewPropsChanged: false, platformWrites: 0,
|
|
600
|
+
previewAdapter: config.includes('@promptframe/cli/preview') ? 'configured' : 'setup_required',
|
|
601
|
+
nextAction: 'Refresh the local preview. Existing custom Vite shells need promptFramePreviewResources().' });
|
|
602
|
+
}
|
|
545
603
|
async function devWorkspace(root, argv) {
|
|
546
604
|
const studioOrigin = valueAfter(argv, '--studio-origin')
|
|
547
605
|
?? fail('Workspace dev requires --studio-origin <exact-origin>.', 'dev.workspace.origin_required', 2);
|
|
@@ -1686,6 +1744,7 @@ function buildVersionNotesHeaders(versionNotes) {
|
|
|
1686
1744
|
return versionNotes ? { 'x-promptframe-version-notes': versionNotes } : {};
|
|
1687
1745
|
}
|
|
1688
1746
|
const POSITIONAL_VALUE_FLAGS = new Set([
|
|
1747
|
+
'--prop', '--file', '--asset-ref',
|
|
1689
1748
|
'--allowed-upload-target',
|
|
1690
1749
|
'--auth-permissions',
|
|
1691
1750
|
'--auth-roles',
|
|
@@ -1875,7 +1934,8 @@ async function loginWithDeviceCode(endpoint, argv) {
|
|
|
1875
1934
|
contractVersion: CLI_AUTH_CONTRACT_VERSION,
|
|
1876
1935
|
endpoint,
|
|
1877
1936
|
clientName: `PromptFrame CLI on ${os.hostname()}`,
|
|
1878
|
-
requestedScopes: DEFAULT_CLI_LOGIN_SCOPES,
|
|
1937
|
+
requestedScopes: [...new Set([...(valuesAfter(argv, '--scope').length ? valuesAfter(argv, '--scope') : DEFAULT_CLI_LOGIN_SCOPES),
|
|
1938
|
+
...(hasFlag(argv, '--with-assets') ? ['asset.read'] : [])])],
|
|
1879
1939
|
}),
|
|
1880
1940
|
}, 'login.device_start.failed');
|
|
1881
1941
|
const deviceCode = requiredPayloadString(startPayload, 'deviceCode', 'login.device_start.invalid');
|
|
@@ -3020,18 +3080,12 @@ function resolveBearerToken(endpoint, argv) {
|
|
|
3020
3080
|
?? process.env.PROMPTFRAME_CI_TOKEN
|
|
3021
3081
|
?? process.env.PROMPTFRAME_CLI_TOKEN
|
|
3022
3082
|
?? process.env.PROMPTFRAME_AUTH_TOKEN;
|
|
3023
|
-
|
|
3024
|
-
return explicit;
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
return
|
|
3028
|
-
if (normalizeEndpoint(stringValue(credential.endpoint) ?? '') !== normalizeEndpoint(endpoint))
|
|
3029
|
-
return undefined;
|
|
3030
|
-
const expiresAt = stringValue(credential.expiresAt);
|
|
3031
|
-
if (expiresAt && Date.parse(expiresAt) <= Date.now()) {
|
|
3032
|
-
fail('Stored PromptFrame CLI credential is expired. Run promptframe login again.', 'cli.auth.token_expired', 2);
|
|
3083
|
+
try {
|
|
3084
|
+
return cliBearerToken({ endpoint, explicit, configuration: readConfig(argv) });
|
|
3085
|
+
}
|
|
3086
|
+
catch {
|
|
3087
|
+
return fail('Stored PromptFrame CLI credential is expired. Run promptframe login again.', 'cli.auth.token_expired', 2);
|
|
3033
3088
|
}
|
|
3034
|
-
return stringValue(credential.tokenSecret);
|
|
3035
3089
|
}
|
|
3036
3090
|
function describeAuthForEndpoint(endpoint, argv) {
|
|
3037
3091
|
const credential = asRecord(readConfig(argv).credential);
|
|
@@ -3170,15 +3224,7 @@ function fileCredentialWarning() {
|
|
|
3170
3224
|
};
|
|
3171
3225
|
}
|
|
3172
3226
|
function readConfig(argv) {
|
|
3173
|
-
|
|
3174
|
-
if (!existsSync(path))
|
|
3175
|
-
return {};
|
|
3176
|
-
try {
|
|
3177
|
-
return JSON.parse(readFileSync(path, 'utf8'));
|
|
3178
|
-
}
|
|
3179
|
-
catch {
|
|
3180
|
-
return {};
|
|
3181
|
-
}
|
|
3227
|
+
return readCliConfiguration(resolveConfigPath(argv));
|
|
3182
3228
|
}
|
|
3183
3229
|
function writeConfig(argv, config) {
|
|
3184
3230
|
const path = resolveConfigPath(argv);
|
|
@@ -3317,6 +3363,15 @@ function validatePreviewProps(dir, manifest) {
|
|
|
3317
3363
|
assertStaticSchemaResolved(schemaFacts, manifest.entry.propsSchemaPath);
|
|
3318
3364
|
assertPreviewPropsMatchStaticSchema(manifest, preview, schemaFacts);
|
|
3319
3365
|
assertStaticPropsHaveDescriptions(schemaFacts, manifest.entry.propsSchemaPath);
|
|
3366
|
+
let references;
|
|
3367
|
+
try {
|
|
3368
|
+
references = collectPromptFrameResourceReferences({ type: 'object', properties: schemaFacts.properties }, preview.props ?? {});
|
|
3369
|
+
}
|
|
3370
|
+
catch {
|
|
3371
|
+
fail('Public preview resource fields must use valid example paths.', 'component_standard.preview.resource_invalid');
|
|
3372
|
+
}
|
|
3373
|
+
if (references.some(row => row.source !== 'public'))
|
|
3374
|
+
fail('Private resource selections belong in resource set drafts; public preview props must use package examples.', 'component_standard.preview.private_resource_reference');
|
|
3320
3375
|
}
|
|
3321
3376
|
function assertPreviewDurationMatchesManifest(preview, manifest) {
|
|
3322
3377
|
const durationFrames = Number(preview.durationFrames);
|
|
@@ -3731,8 +3786,8 @@ function classifyPreviewShell(source) {
|
|
|
3731
3786
|
}
|
|
3732
3787
|
return 'custom_or_unknown';
|
|
3733
3788
|
}
|
|
3734
|
-
function renderPromptFrameThinPreviewRoot() {
|
|
3735
|
-
|
|
3789
|
+
function renderPromptFrameThinPreviewRoot(localResources = false) {
|
|
3790
|
+
const source = `import { Player } from '@remotion/player';
|
|
3736
3791
|
import {
|
|
3737
3792
|
PromptFramePreviewApp,
|
|
3738
3793
|
resolvePromptFramePreviewLocale,
|
|
@@ -3801,6 +3856,17 @@ createRoot(root).render(
|
|
|
3801
3856
|
</StrictMode>,
|
|
3802
3857
|
);
|
|
3803
3858
|
`;
|
|
3859
|
+
if (!localResources)
|
|
3860
|
+
return source;
|
|
3861
|
+
return source
|
|
3862
|
+
.replace("import { propsSchema, type ComponentProps } from './schema';", "import { propsSchema, type ComponentProps } from './schema';\nimport { promptFrameLocalPreview } from 'virtual:promptframe-local-preview';")
|
|
3863
|
+
.replace('const initialPropsParse = propsSchema.safeParse(preview.props ?? {});', 'async function mountPreview() {\nconst localPreview = await promptFrameLocalPreview;\nconst initialPropsParse = propsSchema.safeParse(localPreview.props ?? preview.props ?? {});')
|
|
3864
|
+
.replace(' <StrictMode>\n <PromptFramePreviewApp', ' <StrictMode>\n {localPreview.issues.length > 0 && <p role="alert" style={{ padding: 12 }}>\n 本地预览素材不可用,当前显示包内示例。请核对所选文件、作品与 CLI 素材读取授权后刷新。\n </p>}\n <PromptFramePreviewApp')
|
|
3865
|
+
+ '\n}\nvoid mountPreview();\n';
|
|
3866
|
+
}
|
|
3867
|
+
function hasResourcePreviewAdapter(dir) {
|
|
3868
|
+
const path = join(dir, 'vite.config.ts');
|
|
3869
|
+
return existsSync(path) && readFileSync(path, 'utf8').includes('@promptframe/cli/preview');
|
|
3804
3870
|
}
|
|
3805
3871
|
function assertPublicResourcesAccepted(report) {
|
|
3806
3872
|
const firstError = report.diagnostics.find((item) => item.severity === 'error');
|
|
@@ -4361,6 +4427,8 @@ Commands:
|
|
|
4361
4427
|
sync <dir> Refresh PromptFrame-generated authoring shell files (--dry-run by default; use --apply)
|
|
4362
4428
|
preview <dir> Validate and print local Remotion preview envelope
|
|
4363
4429
|
--write-local-report Write .promptframe/local-previews/preview-report.json
|
|
4430
|
+
resource set <dir> Select a private local preview resource (--prop /field, --file path OR --asset-ref ref --session-id id)
|
|
4431
|
+
resource status|clear <dir> Inspect or clear private preview selections; original files are retained
|
|
4364
4432
|
dev <dir> Start a local preview or workspace checked-module connection
|
|
4365
4433
|
--studio-origin <origin> Required for a multi-component workspace
|
|
4366
4434
|
--idle-timeout <minutes> Workspace idle exit (default 30; 0 disables)
|
|
@@ -4377,6 +4445,7 @@ Commands:
|
|
|
4377
4445
|
probe <buildId> --level <level> Rerun component layout/security probe
|
|
4378
4446
|
login --endpoint <url> Start browser login code flow and store a CLI token
|
|
4379
4447
|
--token <token> Verify and store an already issued CLI/CI token
|
|
4448
|
+
--with-assets Explicitly request asset.read in the normal browser authorization
|
|
4380
4449
|
whoami Show the current PromptFrame CLI identity
|
|
4381
4450
|
logout Revoke the current CLI token and clear local config
|
|
4382
4451
|
discovery Fetch platform endpoint and self-service capabilities
|