parley-live 0.4.2 → 0.5.1
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 +1 -0
- package/dist/index.js +8 -2
- package/dist/lens.js +252 -0
- package/kb/index/bm25.json +1 -0
- package/kb/index/chunks-meta.jsonl +11523 -0
- package/lens-builder/build-from-prompt.mjs +19 -0
- package/lens-builder/build.mjs +147 -0
- package/lens-builder/cli.mjs +103 -0
- package/lens-builder/kb/lib-fetch.mjs +35 -0
- package/lens-builder/kb/search.mjs +61 -0
- package/lens-builder/kb/show.mjs +4 -0
- package/lens-builder/kb/tokenize.mjs +27 -0
- package/lens-builder/lib/bridge.mjs +186 -0
- package/lens-builder/lib/submission.mjs +246 -0
- package/lens-builder/mcp-client.mjs +101 -0
- package/lens-builder/pitch/one-pager.mjs +70 -0
- package/lens-builder/planner.mjs +108 -0
- package/lens-builder/publish.mjs +127 -0
- package/lens-builder/training/author-scene.ts +77 -0
- package/lens-builder/training/compile.mjs +258 -0
- package/lens-builder/vendor/specs-publish/LICENSE +208 -0
- package/lens-builder/vendor/specs-publish/NOTICE +13 -0
- package/lens-builder/vendor/specs-publish/scripts/make-eec-script.py +85 -0
- package/lens-builder/vendor/specs-publish/scripts/package.ts +189 -0
- package/lens-builder/vendor/specs-publish/scripts/preflight.ts +852 -0
- package/lens-builder/vendor/specs-publish/scripts/set-lens-icon.ts +107 -0
- package/lens-builder/vendor/specs-publish/scripts/set-lens-name.ts +121 -0
- package/lens-builder/vendor/specs-publish/scripts/set-signing-key.ts +129 -0
- package/lens-builder/vendor/specs-publish/scripts/signing-key.js +290 -0
- package/lens-builder/verify.mjs +186 -0
- package/lens-builder/webxr/generate.mjs +238 -0
- package/package.json +11 -5
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Copyright 2026 Specs Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
// publish · PACKAGE (Editor API)
|
|
5
|
+
// Run AS-IS via ExecuteEditorCode — zero config. Pass this file's path as `path`; do NOT read it.
|
|
6
|
+
//
|
|
7
|
+
// Saves the project, waits for background tasks, then exports a PRODUCTION-signed SPK to
|
|
8
|
+
// <project>/.export/<name>.spk and returns its base64 SHA-256 checksum. This is the
|
|
9
|
+
// expensive phase — run it once and reuse the cached result; never re-export after a
|
|
10
|
+
// backend-only prompt (org/category/account).
|
|
11
|
+
//
|
|
12
|
+
// NOTE: SPK export deliberately uses LensStudio:Engine + LensStudio:Spk. These modules
|
|
13
|
+
// may be hidden from public Support/editor.d.ts builds, so import them through a
|
|
14
|
+
// non-literal specifier and treat them as runtime-checked internal APIs.
|
|
15
|
+
//
|
|
16
|
+
// Result shapes:
|
|
17
|
+
// { status: "EXPORTED", packagePath, cleanupPath, checksum, packageBytes,
|
|
18
|
+
// packageId, lensName, projectPath, generatedPackage: true }
|
|
19
|
+
// { status: "ACTION_REQUIRED", reason, message, ... } ← ask the user, then retry
|
|
20
|
+
// { status: "FAILED", reason, message, stack? }
|
|
21
|
+
//
|
|
22
|
+
// Runtime note: ExecuteEditorCode's JS runtime does NOT fire setTimeout callbacks. Do not
|
|
23
|
+
// introduce setTimeout-based sleeps in this script — they hang forever. exporter.exportLens()
|
|
24
|
+
// is synchronous; whenAllCompleted() drains follow-on tasks. That's the full ordering signal.
|
|
25
|
+
|
|
26
|
+
const importEditorModule = async (name: string): Promise<any> => await import("LensStudio:" + name);
|
|
27
|
+
|
|
28
|
+
const FileSystem = await import("LensStudio:FileSystem");
|
|
29
|
+
const Crypto = await import("LensStudio:Crypto");
|
|
30
|
+
const EngineApi: any = await importEditorModule("Engine");
|
|
31
|
+
const SpkApi: any = await importEditorModule("Spk");
|
|
32
|
+
|
|
33
|
+
function errorToString(error: unknown): string {
|
|
34
|
+
return error instanceof Error ? error.message : String(error);
|
|
35
|
+
}
|
|
36
|
+
function stripYamlScalarQuotes(value: string | undefined): string {
|
|
37
|
+
return (value ?? "").trim().replace(/^["']/, "").replace(/["']$/, "");
|
|
38
|
+
}
|
|
39
|
+
function readProjectScalar(text: string, key: string): string {
|
|
40
|
+
const match = text.match(new RegExp(`(?:^|\\n)\\s*${key}:\\s*([^\\r\\n]*)`));
|
|
41
|
+
return stripYamlScalarQuotes(match?.[1]);
|
|
42
|
+
}
|
|
43
|
+
function oneLine(value: string): string {
|
|
44
|
+
return value.replace(/\s+/g, " ").trim();
|
|
45
|
+
}
|
|
46
|
+
function actionRequired(reason: string, message: string, extra: Record<string, unknown> = {}): any {
|
|
47
|
+
return { status: "ACTION_REQUIRED", stage: "package", reason, message, ...extra };
|
|
48
|
+
}
|
|
49
|
+
function failed(reason: string, message: string, extra: Record<string, unknown> = {}): any {
|
|
50
|
+
return { status: "FAILED", stage: "package", reason, message, ...extra };
|
|
51
|
+
}
|
|
52
|
+
function bytesToBase64(input: ArrayBuffer | Uint8Array): string {
|
|
53
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
54
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
55
|
+
let output = "";
|
|
56
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
57
|
+
const a = bytes[i];
|
|
58
|
+
const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
59
|
+
const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
60
|
+
const triplet = (a << 16) | (b << 8) | c;
|
|
61
|
+
output += alphabet[(triplet >> 18) & 63];
|
|
62
|
+
output += alphabet[(triplet >> 12) & 63];
|
|
63
|
+
output += i + 1 < bytes.length ? alphabet[(triplet >> 6) & 63] : "=";
|
|
64
|
+
output += i + 2 < bytes.length ? alphabet[triplet & 63] : "=";
|
|
65
|
+
}
|
|
66
|
+
return output;
|
|
67
|
+
}
|
|
68
|
+
function createProductionSpkPacker(signingKey: Editor.Path): any {
|
|
69
|
+
// SpkPacker's signature has varied across Lens Studio versions — try two-arg, then one-arg.
|
|
70
|
+
try {
|
|
71
|
+
return new SpkApi.SpkPacker(signingKey, false);
|
|
72
|
+
} catch (twoArgError) {
|
|
73
|
+
try {
|
|
74
|
+
return new SpkApi.SpkPacker(signingKey);
|
|
75
|
+
} catch (oneArgError) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Could not create production SPK packer. twoArg=${errorToString(twoArgError)}; oneArg=${errorToString(oneArgError)}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function waitForProjectTasks(): Promise<any | null> {
|
|
83
|
+
try {
|
|
84
|
+
const taskManager = pluginSystem.findInterface(Task.ITaskManager);
|
|
85
|
+
await taskManager.whenAllCompleted();
|
|
86
|
+
return null;
|
|
87
|
+
} catch (taskError) {
|
|
88
|
+
return actionRequired("pending_tasks_unavailable", "Could not wait for Lens Studio background tasks before export.", {
|
|
89
|
+
error: errorToString(taskError),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function packageDigest(packagePath: Editor.Path): Promise<{ checksum: string; packageBytes: number }> {
|
|
94
|
+
const packageBytes = FileSystem.readBytes(packagePath);
|
|
95
|
+
const checksum = bytesToBase64(await Crypto.subtle.digest("SHA-256", packageBytes));
|
|
96
|
+
return { checksum, packageBytes: packageBytes.length };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const auth = pluginSystem.findInterface(Editor.IAuthorization);
|
|
101
|
+
if (!auth) {
|
|
102
|
+
return actionRequired("no_auth_interface", "Lens Studio authorization is unavailable. Sign in to Lens Studio, then retry.");
|
|
103
|
+
}
|
|
104
|
+
if (!auth.isAuthorized) {
|
|
105
|
+
return actionRequired("not_signed_in", "Sign in to Lens Studio, then retry.");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const project = pluginSystem.findInterface(Editor.Model.IModel).project;
|
|
109
|
+
const projectPath = project.projectFile.toString();
|
|
110
|
+
const projectText = FileSystem.readFile(project.projectFile);
|
|
111
|
+
const packageId = oneLine(readProjectScalar(projectText, "packageId"));
|
|
112
|
+
const lensName = oneLine(stripYamlScalarQuotes(project.metaInfo.lensName) || readProjectScalar(projectText, "lensName"));
|
|
113
|
+
if (!packageId || !lensName) {
|
|
114
|
+
const message =
|
|
115
|
+
!packageId && !lensName
|
|
116
|
+
? "The project needs a package ID and a Lens name before it can be submitted."
|
|
117
|
+
: !packageId
|
|
118
|
+
? "The project needs a package ID before it can be submitted."
|
|
119
|
+
: "The project needs a Lens name before it can be submitted.";
|
|
120
|
+
return actionRequired(
|
|
121
|
+
"missing_submission_metadata",
|
|
122
|
+
message,
|
|
123
|
+
{ projectPath, packageId, lensName },
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const signingKey = project.metaInfo.spkProductionKeyPath;
|
|
128
|
+
if (!signingKey || signingKey.isEmpty || !FileSystem.exists(signingKey)) {
|
|
129
|
+
return actionRequired(
|
|
130
|
+
"no_prod_signing_key",
|
|
131
|
+
"This project needs a production signing key before export. Generate or add one (reusing an existing key is fine) in Project Settings > SPECS Settings.",
|
|
132
|
+
{ projectPath },
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
project.save();
|
|
137
|
+
const preExportTaskFailure = await waitForProjectTasks();
|
|
138
|
+
if (preExportTaskFailure) {
|
|
139
|
+
return preExportTaskFailure;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const exportDir = project.projectDirectory.appended(new Editor.Path(".export"));
|
|
143
|
+
if (!FileSystem.exists(exportDir)) {
|
|
144
|
+
FileSystem.createDir(exportDir, { recursive: true });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const packagePath = exportDir.appended(new Editor.Path(`${project.projectFile.fileNameBase}.spk`));
|
|
148
|
+
const strategy = new EngineApi.Lens.Export.Strategy();
|
|
149
|
+
strategy.type = EngineApi.Lens.Export.Type.ClientLens;
|
|
150
|
+
strategy.packer = createProductionSpkPacker(signingKey);
|
|
151
|
+
|
|
152
|
+
const exportOptions = new EngineApi.ExportOptions();
|
|
153
|
+
exportOptions.skipSizeCalculation = true;
|
|
154
|
+
|
|
155
|
+
const engine = EngineApi.create(project.cacheDirectory);
|
|
156
|
+
const exporter = engine.createExporter();
|
|
157
|
+
exporter.exportLens(project.scene, packagePath, project.metaInfo, strategy, exportOptions);
|
|
158
|
+
const postExportTaskFailure = await waitForProjectTasks();
|
|
159
|
+
if (postExportTaskFailure) {
|
|
160
|
+
return postExportTaskFailure;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!FileSystem.exists(packagePath)) {
|
|
164
|
+
return failed("package_missing_after_export", "Lens Studio export returned but the expected package file was not created.", {
|
|
165
|
+
packagePath: packagePath.toString(),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// exporter.exportLens() is synchronous and writes the SPK in full before returning;
|
|
170
|
+
// the post-export whenAllCompleted() above drains any follow-on tasks. No sleep needed
|
|
171
|
+
// (and setTimeout() callbacks don't fire inside ExecuteEditorCode's JS runtime).
|
|
172
|
+
const digest = await packageDigest(packagePath);
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
status: "EXPORTED",
|
|
176
|
+
stage: "package",
|
|
177
|
+
projectPath,
|
|
178
|
+
packagePath: packagePath.toString(),
|
|
179
|
+
cleanupPath: packagePath.toString(),
|
|
180
|
+
packageId,
|
|
181
|
+
lensName,
|
|
182
|
+
signingKeyPath: signingKey.toString(),
|
|
183
|
+
generatedPackage: true,
|
|
184
|
+
packageBytes: digest.packageBytes,
|
|
185
|
+
checksum: digest.checksum,
|
|
186
|
+
};
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return failed("exception", errorToString(error), { stack: error instanceof Error ? error.stack : undefined });
|
|
189
|
+
}
|