@hraness/slopcamera 3.2.7 → 3.2.8
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/NOTICE.md +1 -7
- package/PRIVACY.md +16 -7
- package/README.md +37 -12
- package/apps/desktop/README.md +14 -130
- package/apps/desktop/application/context.ts +0 -9
- package/apps/desktop/application/default-registry.ts +0 -10
- package/apps/desktop/application/operation.ts +1 -5
- package/apps/desktop/application/operations/index.ts +0 -1
- package/apps/desktop/cli/args.ts +14 -86
- package/apps/desktop/cli/command-host-resources.ts +2 -1
- package/apps/desktop/cli/commands.ts +28 -67
- package/apps/desktop/cli/help.ts +12 -18
- package/apps/desktop/cli/html-scene.ts +139 -28
- package/apps/desktop/cli/io.ts +2 -1
- package/apps/desktop/cli/main.ts +23 -47
- package/apps/desktop/cli/menubar.ts +244 -0
- package/apps/desktop/cli/music-analysis-service.ts +61 -0
- package/apps/desktop/cli/portable-surface.ts +12 -4
- package/apps/desktop/code/application-node-planner.ts +0 -47
- package/apps/desktop/code/host-source-layout.ts +46 -0
- package/apps/desktop/code/public.ts +0 -1
- package/apps/desktop/code/runtime-identity.ts +50 -8
- package/apps/desktop/code/semantic-builder.ts +0 -43
- package/apps/desktop/code/source-bundle.ts +23 -6
- package/apps/desktop/code/source-typecheck.ts +131 -43
- package/apps/desktop/code/worker-client.ts +14 -2
- package/apps/desktop/core/music-analysis.ts +124 -1
- package/apps/desktop/dist/cli/main.js +244 -250
- package/apps/desktop/html-overlay/audio-reactivity.ts +127 -0
- package/apps/desktop/html-overlay/index.ts +9 -0
- package/apps/desktop/html-overlay/runtime.ts +2 -0
- package/apps/desktop/html-overlay/scene.ts +29 -0
- package/dist/cli.js +83 -81
- package/dist/{index-rvghzt7b.js → index-7131pg1c.js} +43 -236
- package/dist/{index-mcy8z0br.js → index-fava6pge.js} +1 -1
- package/dist/{index-z7239b4h.js → index-h1k0fnjq.js} +1 -1
- package/dist/{index-p63wavx0.js → index-zfnddgay.js} +1 -1
- package/dist/index.js +4 -18
- package/dist/operations.js +2 -2
- package/dist/vectorize/worker.js +1 -1
- package/dist/workflow.js +3 -3
- package/docs/README.md +1 -1
- package/docs/studio.md +1 -1
- package/package.json +6 -21
- package/skills/slopcamera/SKILL.md +8 -0
- package/skills/slopcamera/references/diagrams.md +5 -14
- package/skills/slopcamera/references/install.md +1 -1
- package/skills/slopcamera/references/music-video.md +23 -3
- package/skills/slopcamera/references/reference-led-3d.md +1 -1
- package/skills/slopcamera/references/support.md +25 -0
- package/skills/slopcamera/references/web-media-excerpts.md +120 -0
- package/src/cli.ts +28 -98
- package/src/index.ts +0 -23
- package/src/support-completion.ts +16 -0
- package/src/support.ts +42 -0
- package/src/version.ts +1 -1
- package/apps/desktop/application/operations/recording/index.ts +0 -5
- package/apps/desktop/application/operations/recording/pause.ts +0 -34
- package/apps/desktop/application/operations/recording/resume.ts +0 -34
- package/apps/desktop/application/operations/recording/shared.ts +0 -199
- package/apps/desktop/application/operations/recording/start.ts +0 -169
- package/apps/desktop/application/operations/recording/stop.ts +0 -34
- package/apps/desktop/capture/protocol.ts +0 -689
- package/apps/desktop/cli/capture-bundle.ts +0 -1117
- package/apps/desktop/cli/recording-controller.ts +0 -1567
- package/apps/desktop/cli/recording-daemon.ts +0 -931
- package/src/desktop.ts +0 -253
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
extname,
|
|
10
10
|
join,
|
|
11
11
|
relative,
|
|
12
|
-
resolve,
|
|
13
12
|
sep,
|
|
14
13
|
} from "node:path";
|
|
15
14
|
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
WorkflowRuntimeIdentitySchema,
|
|
32
31
|
type WorkflowRuntimeIdentity,
|
|
33
32
|
} from "./contracts";
|
|
33
|
+
import { hostSourceRoots } from "./host-source-layout";
|
|
34
34
|
import type { WorkflowSourceBundle } from "./source-bundle";
|
|
35
35
|
|
|
36
36
|
export interface CreateWorkflowRuntimeIdentityOptions {
|
|
@@ -38,7 +38,7 @@ export interface CreateWorkflowRuntimeIdentityOptions {
|
|
|
38
38
|
readonly bundle: WorkflowSourceBundle;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const APPLICATION_BUILD_DOMAIN = "studio.application-build/
|
|
41
|
+
const APPLICATION_BUILD_DOMAIN = "studio.application-build/v2";
|
|
42
42
|
const HOST_APPLICATION_BUILD_DOMAIN = "studio.host-application-build/v1";
|
|
43
43
|
const APPLICATION_SOURCE_EXTENSIONS = new Set([
|
|
44
44
|
".json",
|
|
@@ -52,17 +52,23 @@ const APPLICATION_SOURCE_EXTENSIONS = new Set([
|
|
|
52
52
|
const DESKTOP_SOURCE_DIRECTORIES = [
|
|
53
53
|
"analysis",
|
|
54
54
|
"application",
|
|
55
|
-
"capture",
|
|
56
55
|
"cli",
|
|
57
56
|
"code",
|
|
58
57
|
"contracts",
|
|
59
58
|
"core",
|
|
60
|
-
"runtime",
|
|
61
59
|
"studio",
|
|
62
60
|
"workflows",
|
|
63
61
|
] as const;
|
|
64
62
|
const MAXIMUM_APPLICATION_SOURCE_FILES = 4_096;
|
|
65
63
|
const MAXIMUM_APPLICATION_SOURCE_FILE_BYTES = 64 * 1024 * 1024;
|
|
64
|
+
// The reviewed packed boundary never ships the Zig runtime build tree or the
|
|
65
|
+
// root lockfile, while the committed CLI bundle ships beside the checked
|
|
66
|
+
// sources in both layouts. Each of these inputs stays hash-bound wherever it
|
|
67
|
+
// is present and is skipped only when it is absent.
|
|
68
|
+
const OPTIONAL_APPLICATION_SOURCE_FILES = new Set<string>([
|
|
69
|
+
"apps/desktop/dist/cli/main.js",
|
|
70
|
+
"bun.lock",
|
|
71
|
+
]);
|
|
66
72
|
let cachedApplicationBuild: Promise<string> | undefined;
|
|
67
73
|
|
|
68
74
|
function isWithin(root: string, candidate: string): boolean {
|
|
@@ -137,6 +143,22 @@ async function collectSourceFiles(
|
|
|
137
143
|
}
|
|
138
144
|
}
|
|
139
145
|
|
|
146
|
+
async function presentDesktopDirectory(
|
|
147
|
+
desktopRoot: string,
|
|
148
|
+
directory: string,
|
|
149
|
+
): Promise<string | undefined> {
|
|
150
|
+
const path = join(desktopRoot, directory);
|
|
151
|
+
try {
|
|
152
|
+
if ((await lstat(path)).isDirectory()) return path;
|
|
153
|
+
return undefined;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
async function computeApplicationBuildIdentity(options: {
|
|
141
163
|
readonly desktopRoot: string;
|
|
142
164
|
readonly repositoryRoot: string;
|
|
@@ -151,9 +173,16 @@ async function computeApplicationBuildIdentity(options: {
|
|
|
151
173
|
}
|
|
152
174
|
const sources: Array<{ readonly logicalPath: string; readonly path: string }> = [];
|
|
153
175
|
for (const directory of DESKTOP_SOURCE_DIRECTORIES) {
|
|
176
|
+
const path = await presentDesktopDirectory(desktopRoot, directory);
|
|
177
|
+
if (path === undefined) {
|
|
178
|
+
throw new ApplicationError(
|
|
179
|
+
"not-found",
|
|
180
|
+
`Application build source directory is missing: apps/desktop/${directory}`,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
154
183
|
await collectSourceFiles(
|
|
155
184
|
desktopRoot,
|
|
156
|
-
|
|
185
|
+
path,
|
|
157
186
|
`apps/desktop/${directory}`,
|
|
158
187
|
sources,
|
|
159
188
|
);
|
|
@@ -176,10 +205,20 @@ async function computeApplicationBuildIdentity(options: {
|
|
|
176
205
|
);
|
|
177
206
|
}
|
|
178
207
|
for (const [logicalPath, path] of [
|
|
208
|
+
["apps/desktop/dist/cli/main.js", join(desktopRoot, "dist", "cli", "main.js")],
|
|
179
209
|
["bun.lock", join(repositoryRoot, "bun.lock")],
|
|
180
210
|
["package.json", join(repositoryRoot, "package.json")],
|
|
181
211
|
] as const) {
|
|
182
|
-
|
|
212
|
+
let physical: string;
|
|
213
|
+
try {
|
|
214
|
+
physical = await realpath(path);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (
|
|
217
|
+
OPTIONAL_APPLICATION_SOURCE_FILES.has(logicalPath)
|
|
218
|
+
&& error instanceof Error && "code" in error && error.code === "ENOENT"
|
|
219
|
+
) continue;
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
183
222
|
if (!isWithin(repositoryRoot, physical)) {
|
|
184
223
|
throw new ApplicationError("unsafe-path", `Application build source escapes: ${logicalPath}`);
|
|
185
224
|
}
|
|
@@ -227,8 +266,11 @@ export async function createApplicationBuildIdentity(options: {
|
|
|
227
266
|
readonly desktopRoot?: string;
|
|
228
267
|
readonly repositoryRoot?: string;
|
|
229
268
|
} = {}): Promise<string> {
|
|
230
|
-
|
|
231
|
-
|
|
269
|
+
// Inside the committed bundle, import.meta.dir is apps/desktop/dist/cli;
|
|
270
|
+
// the checked host sources stay at their installed paths below apps/desktop.
|
|
271
|
+
const defaults = hostSourceRoots(import.meta.dir);
|
|
272
|
+
const defaultDesktopRoot = defaults.desktopRoot;
|
|
273
|
+
const defaultRepositoryRoot = defaults.repositoryRoot;
|
|
232
274
|
if (options.desktopRoot !== undefined || options.repositoryRoot !== undefined) {
|
|
233
275
|
return await computeApplicationBuildIdentity({
|
|
234
276
|
desktopRoot: options.desktopRoot ?? defaultDesktopRoot,
|
|
@@ -50,11 +50,6 @@ import type {
|
|
|
50
50
|
ProjectRenderPlanOutput,
|
|
51
51
|
ProjectSnapshotOutput,
|
|
52
52
|
PromoteVariantSelectionOutput,
|
|
53
|
-
RecordingPauseOutput,
|
|
54
|
-
RecordingResumeOutput,
|
|
55
|
-
RecordingStartInput,
|
|
56
|
-
RecordingStartOutput,
|
|
57
|
-
RecordingStopOutput,
|
|
58
53
|
SceneAnalysisOperationInput,
|
|
59
54
|
SceneAnalysisOperationOutput,
|
|
60
55
|
SelectVariantInput,
|
|
@@ -301,8 +296,6 @@ export type MediaAudioEffectsOptions =
|
|
|
301
296
|
OperationInputValue<MediaAudioEffectsInput>;
|
|
302
297
|
export type MediaColorGradeOptions =
|
|
303
298
|
OperationInputValue<MediaColorGradeInput>;
|
|
304
|
-
export type RecordingStartOptions =
|
|
305
|
-
OperationInputValue<RecordingStartInput>;
|
|
306
299
|
|
|
307
300
|
export type FaceFollowOptions = {
|
|
308
301
|
readonly [Key in keyof Omit<FollowFacesInput, "project">]:
|
|
@@ -1344,42 +1337,6 @@ export class WorkflowBuilder {
|
|
|
1344
1337
|
}, options),
|
|
1345
1338
|
});
|
|
1346
1339
|
|
|
1347
|
-
readonly recording = Object.freeze({
|
|
1348
|
-
pause: (
|
|
1349
|
-
key: string,
|
|
1350
|
-
options?: OperationNodeOptions,
|
|
1351
|
-
): Ref<RecordingPauseOutput> => this.#graph.operationByKind(key, {
|
|
1352
|
-
input: {},
|
|
1353
|
-
kind: "recording.pause",
|
|
1354
|
-
version: 1,
|
|
1355
|
-
}, options),
|
|
1356
|
-
resume: (
|
|
1357
|
-
key: string,
|
|
1358
|
-
options?: OperationNodeOptions,
|
|
1359
|
-
): Ref<RecordingResumeOutput> => this.#graph.operationByKind(key, {
|
|
1360
|
-
input: {},
|
|
1361
|
-
kind: "recording.resume",
|
|
1362
|
-
version: 1,
|
|
1363
|
-
}, options),
|
|
1364
|
-
start: (
|
|
1365
|
-
key: string,
|
|
1366
|
-
input: RecordingStartOptions,
|
|
1367
|
-
options?: OperationNodeOptions,
|
|
1368
|
-
): Ref<RecordingStartOutput> => this.#graph.operationByKind(key, {
|
|
1369
|
-
input,
|
|
1370
|
-
kind: "recording.start",
|
|
1371
|
-
version: 2,
|
|
1372
|
-
}, options),
|
|
1373
|
-
stop: (
|
|
1374
|
-
key: string,
|
|
1375
|
-
options?: OperationNodeOptions,
|
|
1376
|
-
): Ref<RecordingStopOutput> => this.#graph.operationByKind(key, {
|
|
1377
|
-
input: {},
|
|
1378
|
-
kind: "recording.stop",
|
|
1379
|
-
version: 1,
|
|
1380
|
-
}, options),
|
|
1381
|
-
});
|
|
1382
|
-
|
|
1383
1340
|
private constructor(graph: WorkflowGraphBuilder) {
|
|
1384
1341
|
this.#graph = graph;
|
|
1385
1342
|
}
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
canonicalJson,
|
|
29
29
|
sha256Hex,
|
|
30
30
|
} from "../core/canonical-json";
|
|
31
|
+
import { hostSourceRoots } from "./host-source-layout";
|
|
31
32
|
import type { WorkflowBundleIdentity as GraphWorkflowBundleIdentity } from "./contracts";
|
|
32
33
|
import { typecheckWorkflowSnapshot } from "./source-typecheck";
|
|
33
34
|
import { captureWorkerProcessStartIdentity } from "./worker-process-identity";
|
|
@@ -52,6 +53,10 @@ const MAX_TIMER_DURATION_MS = 2_147_483_647;
|
|
|
52
53
|
const BUNDLER_GUARDIAN_HANDSHAKE_MS = 2_000;
|
|
53
54
|
const BUNDLER_GUARDIAN_DIAGNOSTIC_BYTES = 2_000;
|
|
54
55
|
|
|
56
|
+
// Spawned helpers always run the checked TypeScript sources, never a path
|
|
57
|
+
// derived from this module's bundled location below apps/desktop/dist/cli.
|
|
58
|
+
const HOST_ROOTS = hostSourceRoots(import.meta.dir);
|
|
59
|
+
|
|
55
60
|
const BUNDLE_SUBPROCESS_SOURCE = String.raw`
|
|
56
61
|
import { fstatSync } from "node:fs";
|
|
57
62
|
const processIdentity = await import(process.argv[5]);
|
|
@@ -756,11 +761,16 @@ async function startBundlerRetirementGuardian(options: {
|
|
|
756
761
|
"--has-lease",
|
|
757
762
|
options.inheritedHostResourceFileDescriptor === 0 ? "false" : "true",
|
|
758
763
|
"--identity-module",
|
|
759
|
-
pathToFileURL(join(
|
|
764
|
+
pathToFileURL(join(
|
|
765
|
+
HOST_ROOTS.desktopRoot,
|
|
766
|
+
"code",
|
|
767
|
+
"worker-process-identity.ts",
|
|
768
|
+
)).href,
|
|
760
769
|
"--host-resource-lock-module",
|
|
761
770
|
pathToFileURL(join(
|
|
762
|
-
|
|
763
|
-
"
|
|
771
|
+
HOST_ROOTS.repositoryRoot,
|
|
772
|
+
"src",
|
|
773
|
+
"host-resource-posix.ts",
|
|
764
774
|
)).href,
|
|
765
775
|
],
|
|
766
776
|
{
|
|
@@ -941,6 +951,7 @@ async function buildWorkflowBundle(
|
|
|
941
951
|
modules: readonly CapturedSourceModule[],
|
|
942
952
|
aliases: Readonly<Record<string, string>>,
|
|
943
953
|
configSearchPath: string,
|
|
954
|
+
hostBoundary: string,
|
|
944
955
|
includeRuntimeTypes: boolean,
|
|
945
956
|
semanticCheck: boolean,
|
|
946
957
|
inheritedHostResourceFileDescriptor: number,
|
|
@@ -979,6 +990,7 @@ async function buildWorkflowBundle(
|
|
|
979
990
|
aliases,
|
|
980
991
|
configSearchPath,
|
|
981
992
|
entryPath,
|
|
993
|
+
hostBoundary,
|
|
982
994
|
includeRuntimeTypes,
|
|
983
995
|
sourceRoot,
|
|
984
996
|
});
|
|
@@ -997,7 +1009,11 @@ async function buildWorkflowBundle(
|
|
|
997
1009
|
outputPath,
|
|
998
1010
|
inheritedHostResourceFileDescriptor === 0 ? "0" : "3",
|
|
999
1011
|
String(maximumBundleBytes),
|
|
1000
|
-
pathToFileURL(join(
|
|
1012
|
+
pathToFileURL(join(
|
|
1013
|
+
HOST_ROOTS.desktopRoot,
|
|
1014
|
+
"code",
|
|
1015
|
+
"worker-process-identity.ts",
|
|
1016
|
+
)).href,
|
|
1001
1017
|
],
|
|
1002
1018
|
{
|
|
1003
1019
|
cwd: sourceRoot,
|
|
@@ -1571,14 +1587,15 @@ async function bundleWorkflowSourceInternal(
|
|
|
1571
1587
|
const aliasSpecifiers = new Set(sourceGraph.bareImports);
|
|
1572
1588
|
const aliases = await bareImportAliases(
|
|
1573
1589
|
[...aliasSpecifiers].sort(),
|
|
1574
|
-
resolve(options.bareImportResolutionRoot ??
|
|
1590
|
+
resolve(options.bareImportResolutionRoot ?? HOST_ROOTS.desktopRoot),
|
|
1575
1591
|
);
|
|
1576
1592
|
const entryRelativePath = relative(allowedRoot, entryPath);
|
|
1577
1593
|
const bytes = await buildWorkflowBundle(
|
|
1578
1594
|
entryRelativePath,
|
|
1579
1595
|
sourceGraph.modules,
|
|
1580
1596
|
aliases,
|
|
1581
|
-
resolve(options.bareImportResolutionRoot ??
|
|
1597
|
+
resolve(options.bareImportResolutionRoot ?? HOST_ROOTS.desktopRoot),
|
|
1598
|
+
HOST_ROOTS.repositoryRoot,
|
|
1582
1599
|
(
|
|
1583
1600
|
sourceGraph.bareImports.some(specifier => (
|
|
1584
1601
|
specifier === "bun" || specifier.startsWith("node:")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
1
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2
2
|
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
|
|
@@ -12,11 +12,38 @@ const WORKFLOW_GLOBALS_SOURCE = [
|
|
|
12
12
|
"declare const process: any;",
|
|
13
13
|
"",
|
|
14
14
|
].join("\n");
|
|
15
|
+
// Packed distributions ship no host tsconfig; this closed fallback preserves
|
|
16
|
+
// the host compiler contract instead of adopting a foreign caller tsconfig.
|
|
17
|
+
const PACKED_WORKFLOW_CONFIG = {
|
|
18
|
+
compilerOptions: {
|
|
19
|
+
allowImportingTsExtensions: true,
|
|
20
|
+
exactOptionalPropertyTypes: true,
|
|
21
|
+
isolatedModules: true,
|
|
22
|
+
jsx: "react-jsx",
|
|
23
|
+
lib: ["ES2023", "DOM", "DOM.Iterable"],
|
|
24
|
+
module: "Preserve",
|
|
25
|
+
moduleDetection: "force",
|
|
26
|
+
moduleResolution: "Bundler",
|
|
27
|
+
noEmit: true,
|
|
28
|
+
noFallthroughCasesInSwitch: true,
|
|
29
|
+
noImplicitOverride: true,
|
|
30
|
+
noImplicitReturns: true,
|
|
31
|
+
noUncheckedIndexedAccess: true,
|
|
32
|
+
noUnusedLocals: true,
|
|
33
|
+
noUnusedParameters: true,
|
|
34
|
+
skipLibCheck: true,
|
|
35
|
+
strict: true,
|
|
36
|
+
target: "ES2023",
|
|
37
|
+
useUnknownInCatchVariables: true,
|
|
38
|
+
verbatimModuleSyntax: true,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
15
41
|
|
|
16
42
|
export interface TypecheckWorkflowSnapshotOptions {
|
|
17
43
|
readonly aliases: Readonly<Record<string, string>>;
|
|
18
44
|
readonly configSearchPath: string;
|
|
19
45
|
readonly entryPath: string;
|
|
46
|
+
readonly hostBoundary: string;
|
|
20
47
|
readonly includeRuntimeTypes: boolean;
|
|
21
48
|
readonly sourceRoot: string;
|
|
22
49
|
}
|
|
@@ -26,6 +53,37 @@ function isWithin(root: string, candidate: string): boolean {
|
|
|
26
53
|
return fromRoot === "" || (!fromRoot.startsWith("..") && !isAbsolute(fromRoot));
|
|
27
54
|
}
|
|
28
55
|
|
|
56
|
+
/** Finds the host tsconfig without crossing into a foreign caller tree. */
|
|
57
|
+
function boundedHostConfigPath(
|
|
58
|
+
searchPath: string,
|
|
59
|
+
boundary: string,
|
|
60
|
+
): string | undefined {
|
|
61
|
+
const limit = resolve(boundary);
|
|
62
|
+
let candidate = resolve(searchPath);
|
|
63
|
+
while (isWithin(limit, candidate)) {
|
|
64
|
+
const path = join(candidate, "tsconfig.json");
|
|
65
|
+
if (ts.sys.fileExists(path)) return path;
|
|
66
|
+
const parent = dirname(candidate);
|
|
67
|
+
if (parent === candidate) return undefined;
|
|
68
|
+
candidate = parent;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Resolves the installed @types/bun package from the host tree so runtime
|
|
75
|
+
* types never depend on the caller's working directory or dependencies.
|
|
76
|
+
*/
|
|
77
|
+
function bunTypeRoots(hostBoundary: string): string | undefined {
|
|
78
|
+
try {
|
|
79
|
+
return dirname(dirname(
|
|
80
|
+
Bun.resolveSync("@types/bun/package.json", resolve(hostBoundary)),
|
|
81
|
+
));
|
|
82
|
+
} catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
29
87
|
function diagnosticText(
|
|
30
88
|
diagnostic: ts.Diagnostic,
|
|
31
89
|
sourceRoot: string,
|
|
@@ -77,49 +135,72 @@ function boundedDiagnostics(
|
|
|
77
135
|
export function typecheckWorkflowSnapshot(
|
|
78
136
|
options: TypecheckWorkflowSnapshotOptions,
|
|
79
137
|
): void {
|
|
80
|
-
const configPath =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"tsconfig.json",
|
|
138
|
+
const configPath = boundedHostConfigPath(
|
|
139
|
+
options.configSearchPath,
|
|
140
|
+
options.hostBoundary,
|
|
84
141
|
);
|
|
142
|
+
const hostDirectory = configPath === undefined
|
|
143
|
+
? resolve(options.hostBoundary)
|
|
144
|
+
: dirname(configPath);
|
|
145
|
+
let parsedOptions: ts.CompilerOptions;
|
|
85
146
|
if (configPath === undefined) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
const parsed = ts.parseJsonConfigFileContent(
|
|
148
|
+
PACKED_WORKFLOW_CONFIG,
|
|
149
|
+
ts.sys,
|
|
150
|
+
hostDirectory,
|
|
151
|
+
{
|
|
152
|
+
composite: false,
|
|
153
|
+
declaration: false,
|
|
154
|
+
emitDeclarationOnly: false,
|
|
155
|
+
incremental: false,
|
|
156
|
+
noEmit: true,
|
|
157
|
+
},
|
|
158
|
+
"slopcamera-packed-workflow.tsconfig.json",
|
|
89
159
|
);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
config.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
160
|
+
if (parsed.errors.length > 0) {
|
|
161
|
+
throw new ApplicationError(
|
|
162
|
+
"internal",
|
|
163
|
+
`Workflow semantic checking could not apply its packed TypeScript configuration:\n${
|
|
164
|
+
boundedDiagnostics(parsed.errors, options.sourceRoot)
|
|
165
|
+
}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
parsedOptions = parsed.options;
|
|
169
|
+
} else {
|
|
170
|
+
const config = ts.readConfigFile(configPath, path => ts.sys.readFile(path));
|
|
171
|
+
if (config.error !== undefined) {
|
|
172
|
+
throw new ApplicationError(
|
|
173
|
+
"internal",
|
|
174
|
+
`Workflow semantic checking could not read the host TypeScript configuration: ${
|
|
175
|
+
diagnosticText(config.error, options.sourceRoot)
|
|
176
|
+
}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
const parsed = ts.parseJsonConfigFileContent(
|
|
180
|
+
config.config,
|
|
181
|
+
ts.sys,
|
|
182
|
+
hostDirectory,
|
|
183
|
+
{
|
|
184
|
+
composite: false,
|
|
185
|
+
declaration: false,
|
|
186
|
+
emitDeclarationOnly: false,
|
|
187
|
+
incremental: false,
|
|
188
|
+
noEmit: true,
|
|
189
|
+
},
|
|
190
|
+
configPath,
|
|
119
191
|
);
|
|
192
|
+
if (parsed.errors.length > 0) {
|
|
193
|
+
throw new ApplicationError(
|
|
194
|
+
"internal",
|
|
195
|
+
`Workflow semantic checking could not parse the host TypeScript configuration:\n${
|
|
196
|
+
boundedDiagnostics(parsed.errors, options.sourceRoot)
|
|
197
|
+
}`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
parsedOptions = parsed.options;
|
|
120
201
|
}
|
|
121
202
|
const typecheckImporterPath = resolve(
|
|
122
|
-
|
|
203
|
+
hostDirectory,
|
|
123
204
|
"slopcamera-workflow-typecheck.ts",
|
|
124
205
|
);
|
|
125
206
|
const aliasPaths = Object.fromEntries(
|
|
@@ -132,7 +213,7 @@ export function typecheckWorkflowSnapshot(
|
|
|
132
213
|
const declaration = ts.resolveModuleName(
|
|
133
214
|
specifier,
|
|
134
215
|
typecheckImporterPath,
|
|
135
|
-
|
|
216
|
+
parsedOptions,
|
|
136
217
|
ts.sys,
|
|
137
218
|
).resolvedModule?.resolvedFileName;
|
|
138
219
|
return [
|
|
@@ -143,8 +224,14 @@ export function typecheckWorkflowSnapshot(
|
|
|
143
224
|
];
|
|
144
225
|
}),
|
|
145
226
|
);
|
|
227
|
+
// Runtime-typed workflows use the host's installed @types/bun when it is
|
|
228
|
+
// present and the explicit any-globals shim when it is not.
|
|
229
|
+
const runtimeTypeRoots = options.includeRuntimeTypes
|
|
230
|
+
? bunTypeRoots(options.hostBoundary)
|
|
231
|
+
: undefined;
|
|
232
|
+
const realRuntimeTypes = runtimeTypeRoots !== undefined;
|
|
146
233
|
const compilerOptions: ts.CompilerOptions = {
|
|
147
|
-
...
|
|
234
|
+
...parsedOptions,
|
|
148
235
|
baseUrl: options.sourceRoot,
|
|
149
236
|
composite: false,
|
|
150
237
|
declaration: false,
|
|
@@ -152,10 +239,11 @@ export function typecheckWorkflowSnapshot(
|
|
|
152
239
|
incremental: false,
|
|
153
240
|
noEmit: true,
|
|
154
241
|
paths: {
|
|
155
|
-
...
|
|
242
|
+
...parsedOptions.paths,
|
|
156
243
|
...aliasPaths,
|
|
157
244
|
},
|
|
158
|
-
|
|
245
|
+
...(realRuntimeTypes ? { typeRoots: [runtimeTypeRoots] } : {}),
|
|
246
|
+
types: realRuntimeTypes ? ["bun"] : [],
|
|
159
247
|
};
|
|
160
248
|
delete compilerOptions.tsBuildInfoFile;
|
|
161
249
|
const host = ts.createCompilerHost(compilerOptions, true);
|
|
@@ -189,7 +277,7 @@ export function typecheckWorkflowSnapshot(
|
|
|
189
277
|
options: compilerOptions,
|
|
190
278
|
rootNames: [
|
|
191
279
|
options.entryPath,
|
|
192
|
-
...(
|
|
280
|
+
...(realRuntimeTypes ? [] : [WORKFLOW_GLOBALS_PATH]),
|
|
193
281
|
],
|
|
194
282
|
});
|
|
195
283
|
const diagnostics = program.getSourceFiles()
|
|
@@ -22,6 +22,7 @@ import { z } from "zod";
|
|
|
22
22
|
|
|
23
23
|
import { ApplicationError } from "../application/errors";
|
|
24
24
|
import type { OperationDiscovery } from "../application/registry";
|
|
25
|
+
import { hostSourceRoots } from "./host-source-layout";
|
|
25
26
|
import { canonicalJson } from "../core/canonical-json";
|
|
26
27
|
import {
|
|
27
28
|
AuthoredWorkflowGraphV1Schema,
|
|
@@ -46,6 +47,9 @@ const DEFAULT_TIMEOUT_MS = 30_000;
|
|
|
46
47
|
const DEFAULT_MAXIMUM_DIAGNOSTIC_BYTES = 64 * 1024;
|
|
47
48
|
const CODE_WORKER_CANCEL_GRACE_MS = 250;
|
|
48
49
|
export const MAX_CODE_WORKER_POOL_SIZE = 4;
|
|
50
|
+
// Spawned helpers always run the checked TypeScript sources, never a path
|
|
51
|
+
// derived from this module's bundled location below apps/desktop/dist/cli.
|
|
52
|
+
const HOST_ROOTS = hostSourceRoots(import.meta.dir);
|
|
49
53
|
|
|
50
54
|
const WorkerBuiltWorkflowSchema = z.strictObject({
|
|
51
55
|
graph: AuthoredWorkflowGraphV1Schema,
|
|
@@ -856,7 +860,11 @@ async function startCodeWorkerLeaseGuardian(options: {
|
|
|
856
860
|
"Code-worker host-resource lease descriptor is unsafe to inherit.",
|
|
857
861
|
);
|
|
858
862
|
}
|
|
859
|
-
const guardianEntryPath = join(
|
|
863
|
+
const guardianEntryPath = join(
|
|
864
|
+
HOST_ROOTS.desktopRoot,
|
|
865
|
+
"code",
|
|
866
|
+
"worker-lease-guardian.ts",
|
|
867
|
+
);
|
|
860
868
|
const guardian = spawn(
|
|
861
869
|
options.bunExecutable,
|
|
862
870
|
[
|
|
@@ -1435,7 +1443,11 @@ export async function startCodeWorker(
|
|
|
1435
1443
|
);
|
|
1436
1444
|
}
|
|
1437
1445
|
const workerEntryPath = resolve(
|
|
1438
|
-
options.workerEntryPath ?? join(
|
|
1446
|
+
options.workerEntryPath ?? join(
|
|
1447
|
+
HOST_ROOTS.desktopRoot,
|
|
1448
|
+
"code",
|
|
1449
|
+
"worker-entry.ts",
|
|
1450
|
+
),
|
|
1439
1451
|
);
|
|
1440
1452
|
const workerEntrySha256 = createHash("sha256")
|
|
1441
1453
|
.update(await readFile(workerEntryPath))
|