@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
package/src/index.ts
CHANGED
|
@@ -4,15 +4,6 @@ import {
|
|
|
4
4
|
readDiagramFile,
|
|
5
5
|
renderDiagramFile,
|
|
6
6
|
} from "./artifacts.js"
|
|
7
|
-
import {
|
|
8
|
-
desktopDownloadPage,
|
|
9
|
-
desktopStatus,
|
|
10
|
-
findDesktopApplication,
|
|
11
|
-
getLatestDesktopRelease,
|
|
12
|
-
installDesktop,
|
|
13
|
-
openInDesktop,
|
|
14
|
-
selectDesktopAsset,
|
|
15
|
-
} from "./desktop.js"
|
|
16
7
|
import {
|
|
17
8
|
generateSlopcameraImage,
|
|
18
9
|
generateSlopcameraImageFile,
|
|
@@ -64,27 +55,21 @@ export const slopcameraApi = Object.freeze({
|
|
|
64
55
|
builtInIcons,
|
|
65
56
|
bundledSkillPath,
|
|
66
57
|
checkDiagramFile,
|
|
67
|
-
desktopDownloadPage,
|
|
68
|
-
desktopStatus,
|
|
69
58
|
defineSlopcameraWorkflow,
|
|
70
59
|
DiagramValidationError,
|
|
71
|
-
findDesktopApplication,
|
|
72
60
|
generateSlopcameraImage,
|
|
73
61
|
generateSlopcameraImageFile,
|
|
74
|
-
getLatestDesktopRelease,
|
|
75
62
|
slopcameraGatewayCredentialStatus,
|
|
76
63
|
slopcameraMcpProtocolVersion,
|
|
77
64
|
slopcameraMcpServerName,
|
|
78
65
|
slopcameraMcpTools,
|
|
79
66
|
slopcameraOperationRegistry,
|
|
80
67
|
SlopcameraMcpToolRuntime,
|
|
81
|
-
installDesktop,
|
|
82
68
|
installSkill,
|
|
83
69
|
lintDiagram,
|
|
84
70
|
mcpMaximumRenderedPixels,
|
|
85
71
|
mcpMaximumScale,
|
|
86
72
|
mcpSourceByteLimit,
|
|
87
|
-
openInDesktop,
|
|
88
73
|
parseDiagramSource,
|
|
89
74
|
parseDiagramSpec,
|
|
90
75
|
readDiagramFile,
|
|
@@ -97,7 +82,6 @@ export const slopcameraApi = Object.freeze({
|
|
|
97
82
|
runSlopcameraWorkflow,
|
|
98
83
|
runMcpServer,
|
|
99
84
|
searchSlopcameraOperations,
|
|
100
|
-
selectDesktopAsset,
|
|
101
85
|
serializeTldr,
|
|
102
86
|
stackLayoutDefaults,
|
|
103
87
|
StackLayoutError,
|
|
@@ -116,26 +100,20 @@ export {
|
|
|
116
100
|
builtInIcons,
|
|
117
101
|
bundledSkillPath,
|
|
118
102
|
checkDiagramFile,
|
|
119
|
-
desktopDownloadPage,
|
|
120
|
-
desktopStatus,
|
|
121
103
|
DiagramValidationError,
|
|
122
|
-
findDesktopApplication,
|
|
123
104
|
generateSlopcameraImage,
|
|
124
105
|
generateSlopcameraImageFile,
|
|
125
|
-
getLatestDesktopRelease,
|
|
126
106
|
slopcameraGatewayCredentialStatus,
|
|
127
107
|
slopcameraMcpProtocolVersion,
|
|
128
108
|
slopcameraMcpServerName,
|
|
129
109
|
slopcameraMcpTools,
|
|
130
110
|
slopcameraOperationRegistry,
|
|
131
111
|
SlopcameraMcpToolRuntime,
|
|
132
|
-
installDesktop,
|
|
133
112
|
installSkill,
|
|
134
113
|
lintDiagram,
|
|
135
114
|
mcpMaximumRenderedPixels,
|
|
136
115
|
mcpMaximumScale,
|
|
137
116
|
mcpSourceByteLimit,
|
|
138
|
-
openInDesktop,
|
|
139
117
|
parseDiagramSource,
|
|
140
118
|
parseDiagramSpec,
|
|
141
119
|
readDiagramFile,
|
|
@@ -147,7 +125,6 @@ export {
|
|
|
147
125
|
resolveStackLayout,
|
|
148
126
|
runMcpServer,
|
|
149
127
|
searchSlopcameraOperations,
|
|
150
|
-
selectDesktopAsset,
|
|
151
128
|
serializeTldr,
|
|
152
129
|
stackLayoutDefaults,
|
|
153
130
|
StackLayoutError,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Content-free notification after useful output and owned cleanup complete. */
|
|
2
|
+
export type UsefulResultObserver = () => void | Promise<void>
|
|
3
|
+
|
|
4
|
+
export function reportUsefulResult(observer: UsefulResultObserver | undefined): void {
|
|
5
|
+
try {
|
|
6
|
+
if (observer !== undefined) void Promise.resolve(observer()).catch(() => undefined)
|
|
7
|
+
} catch {
|
|
8
|
+
// Optional presentation cannot change a completed operation's outcome.
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function quietSupportChildEnvironment(
|
|
13
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
14
|
+
): Record<string, string | undefined> {
|
|
15
|
+
return { ...env, HRANESS_SUPPORT_AUDIENCE: "off", HRANESS_SUPPORT_EMAIL: "off" }
|
|
16
|
+
}
|
package/src/support.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
maybeShowSupportInvitation,
|
|
3
|
+
runSupportCommand,
|
|
4
|
+
type SupportCommandOptions,
|
|
5
|
+
} from "@hraness/support-foundation/node"
|
|
6
|
+
|
|
7
|
+
export const supportProfile = {
|
|
8
|
+
id: "slopcamera",
|
|
9
|
+
name: "Slopcamera",
|
|
10
|
+
valueProposition: "Support ongoing development of local visual tools for agents.",
|
|
11
|
+
updates: false,
|
|
12
|
+
} as const
|
|
13
|
+
|
|
14
|
+
/** Called only by the real process entrypoint; imported CLI and SDK calls stay inert. */
|
|
15
|
+
export function standaloneSupportEnvironment(): Readonly<Record<string, string | undefined>> {
|
|
16
|
+
const env = { ...process.env }
|
|
17
|
+
process.env.HRANESS_SUPPORT_AUDIENCE = "off"
|
|
18
|
+
process.env.HRANESS_SUPPORT_EMAIL = "off"
|
|
19
|
+
return env
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function runProductSupportCommand(
|
|
23
|
+
args: readonly string[],
|
|
24
|
+
options: SupportCommandOptions = {},
|
|
25
|
+
): Promise<number> {
|
|
26
|
+
const result = await runSupportCommand(supportProfile, args, {
|
|
27
|
+
command: ["slopcamera"], ...options, gitEmail: false,
|
|
28
|
+
})
|
|
29
|
+
if (result.stdout !== "") process.stdout.write(result.stdout)
|
|
30
|
+
if (result.stderr !== "") process.stderr.write(result.stderr)
|
|
31
|
+
return result.exitCode
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function showProductSupportInvitation(options: SupportCommandOptions = {}): Promise<void> {
|
|
35
|
+
try {
|
|
36
|
+
await maybeShowSupportInvitation(supportProfile, {
|
|
37
|
+
usefulResult: true, command: ["slopcamera"], ...options, gitEmail: false,
|
|
38
|
+
})
|
|
39
|
+
} catch {
|
|
40
|
+
// Optional support must not alter the completed task or its stdout.
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SLOPCAMERA_VERSION = "3.2.
|
|
1
|
+
export const SLOPCAMERA_VERSION = "3.2.8" as const
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { OperationDefinition } from "../../operation";
|
|
2
|
-
import {
|
|
3
|
-
EmptyRecordingOperationInputSchema,
|
|
4
|
-
type EmptyRecordingOperationInput,
|
|
5
|
-
executeRecordingControl,
|
|
6
|
-
RecordingOperationOutputSchema,
|
|
7
|
-
type RecordingOperationOutput,
|
|
8
|
-
recordingTransitionPolicy,
|
|
9
|
-
summarizeRecordingControl,
|
|
10
|
-
} from "./shared";
|
|
11
|
-
|
|
12
|
-
export const RecordingPauseInputSchema = EmptyRecordingOperationInputSchema;
|
|
13
|
-
export const RecordingPauseOutputSchema = RecordingOperationOutputSchema;
|
|
14
|
-
export type RecordingPauseInput = EmptyRecordingOperationInput;
|
|
15
|
-
export type RecordingPauseOutput = RecordingOperationOutput;
|
|
16
|
-
|
|
17
|
-
export const recordingPauseOperationDefinition: OperationDefinition<
|
|
18
|
-
"recording.pause",
|
|
19
|
-
RecordingPauseInput,
|
|
20
|
-
RecordingPauseOutput
|
|
21
|
-
> = {
|
|
22
|
-
inputSchema: RecordingPauseInputSchema,
|
|
23
|
-
inputSchemaId: "slopcamera.operation.recording.pause.input/v1",
|
|
24
|
-
kind: "recording.pause",
|
|
25
|
-
lifecycle: {
|
|
26
|
-
kind: "live-control",
|
|
27
|
-
execute: async context => await executeRecordingControl(context, "pause"),
|
|
28
|
-
},
|
|
29
|
-
outputSchema: RecordingPauseOutputSchema,
|
|
30
|
-
outputSchemaId: "slopcamera.operation.recording.pause.output/v1",
|
|
31
|
-
policy: recordingTransitionPolicy,
|
|
32
|
-
summarize: output => summarizeRecordingControl("recording.pause", output),
|
|
33
|
-
version: 1,
|
|
34
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { OperationDefinition } from "../../operation";
|
|
2
|
-
import {
|
|
3
|
-
EmptyRecordingOperationInputSchema,
|
|
4
|
-
type EmptyRecordingOperationInput,
|
|
5
|
-
executeRecordingControl,
|
|
6
|
-
RecordingOperationOutputSchema,
|
|
7
|
-
type RecordingOperationOutput,
|
|
8
|
-
recordingTransitionPolicy,
|
|
9
|
-
summarizeRecordingControl,
|
|
10
|
-
} from "./shared";
|
|
11
|
-
|
|
12
|
-
export const RecordingResumeInputSchema = EmptyRecordingOperationInputSchema;
|
|
13
|
-
export const RecordingResumeOutputSchema = RecordingOperationOutputSchema;
|
|
14
|
-
export type RecordingResumeInput = EmptyRecordingOperationInput;
|
|
15
|
-
export type RecordingResumeOutput = RecordingOperationOutput;
|
|
16
|
-
|
|
17
|
-
export const recordingResumeOperationDefinition: OperationDefinition<
|
|
18
|
-
"recording.resume",
|
|
19
|
-
RecordingResumeInput,
|
|
20
|
-
RecordingResumeOutput
|
|
21
|
-
> = {
|
|
22
|
-
inputSchema: RecordingResumeInputSchema,
|
|
23
|
-
inputSchemaId: "slopcamera.operation.recording.resume.input/v1",
|
|
24
|
-
kind: "recording.resume",
|
|
25
|
-
lifecycle: {
|
|
26
|
-
kind: "live-control",
|
|
27
|
-
execute: async context => await executeRecordingControl(context, "resume"),
|
|
28
|
-
},
|
|
29
|
-
outputSchema: RecordingResumeOutputSchema,
|
|
30
|
-
outputSchemaId: "slopcamera.operation.recording.resume.output/v1",
|
|
31
|
-
policy: recordingTransitionPolicy,
|
|
32
|
-
summarize: output => summarizeRecordingControl("recording.resume", output),
|
|
33
|
-
version: 1,
|
|
34
|
-
};
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
CapturePermissionsSchema,
|
|
5
|
-
IsoTimestampSchema,
|
|
6
|
-
MicrosecondsSchema,
|
|
7
|
-
RecordingIdSchema,
|
|
8
|
-
} from "../../../contracts";
|
|
9
|
-
import type {
|
|
10
|
-
ApplicationContext,
|
|
11
|
-
ApplicationRecordingController,
|
|
12
|
-
} from "../../context";
|
|
13
|
-
import { ApplicationError } from "../../errors";
|
|
14
|
-
import type {
|
|
15
|
-
BoundedOperationSummary,
|
|
16
|
-
OperationExecutionContext,
|
|
17
|
-
OperationKind,
|
|
18
|
-
OperationPolicy,
|
|
19
|
-
} from "../../operation";
|
|
20
|
-
import { throwIfAborted } from "../shared";
|
|
21
|
-
|
|
22
|
-
export const MAX_RECORDING_OPERATION_DISPLAYS = 16;
|
|
23
|
-
|
|
24
|
-
const DisplayIdSchema = z.string().min(1).max(64);
|
|
25
|
-
const DeviceIdSchema = z.string().min(1).max(256);
|
|
26
|
-
|
|
27
|
-
const ExplicitDisplayIdsSchema = z.array(DisplayIdSchema)
|
|
28
|
-
.min(1)
|
|
29
|
-
.max(MAX_RECORDING_OPERATION_DISPLAYS)
|
|
30
|
-
.superRefine((displayIds, context) => {
|
|
31
|
-
if (new Set(displayIds).size !== displayIds.length) {
|
|
32
|
-
context.addIssue({
|
|
33
|
-
code: "custom",
|
|
34
|
-
message: "Explicit recording display IDs must be unique.",
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
export const RecordingDisplaySelectionSchema = z.discriminatedUnion("kind", [
|
|
40
|
-
z.strictObject({
|
|
41
|
-
kind: z.literal("all"),
|
|
42
|
-
}),
|
|
43
|
-
z.strictObject({
|
|
44
|
-
displayIds: ExplicitDisplayIdsSchema,
|
|
45
|
-
kind: z.literal("selected"),
|
|
46
|
-
}),
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
export const RecordingDeviceSelectionSchema = z.discriminatedUnion("kind", [
|
|
50
|
-
z.strictObject({ kind: z.literal("disabled") }),
|
|
51
|
-
z.strictObject({ kind: z.literal("default") }),
|
|
52
|
-
z.strictObject({ deviceId: DeviceIdSchema, kind: z.literal("device") }),
|
|
53
|
-
]);
|
|
54
|
-
|
|
55
|
-
const RecordingStartFields = {
|
|
56
|
-
camera: RecordingDeviceSelectionSchema,
|
|
57
|
-
displays: RecordingDisplaySelectionSchema,
|
|
58
|
-
microphone: RecordingDeviceSelectionSchema,
|
|
59
|
-
strictInputs: z.boolean(),
|
|
60
|
-
systemAudio: z.boolean(),
|
|
61
|
-
typedText: z.boolean(),
|
|
62
|
-
} as const;
|
|
63
|
-
|
|
64
|
-
export const RecordingStartInputSchema = z.strictObject(
|
|
65
|
-
RecordingStartFields,
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
export const EffectiveRecordingConfigSchema = z.strictObject({
|
|
69
|
-
...RecordingStartFields,
|
|
70
|
-
metadata: z.literal(true),
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const RecordingOperationOutputFields = {
|
|
74
|
-
completedSegmentCount: z.number().int().safe().nonnegative(),
|
|
75
|
-
effectiveConfig: EffectiveRecordingConfigSchema.nullable(),
|
|
76
|
-
logicalTimeUs: MicrosecondsSchema,
|
|
77
|
-
permissions: CapturePermissionsSchema.nullable(),
|
|
78
|
-
recordingId: RecordingIdSchema.nullable(),
|
|
79
|
-
state: z.enum(["idle", "recording", "paused"]),
|
|
80
|
-
updatedAt: IsoTimestampSchema.max(64),
|
|
81
|
-
} as const;
|
|
82
|
-
|
|
83
|
-
export const RecordingOperationOutputSchema = z.strictObject(
|
|
84
|
-
RecordingOperationOutputFields,
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const ControllerRecordingSnapshotSchema = z.strictObject({
|
|
88
|
-
...RecordingOperationOutputFields,
|
|
89
|
-
recordingRoot: z.string().min(1).max(4_096).nullable(),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
export const EmptyRecordingOperationInputSchema = z.strictObject({});
|
|
93
|
-
|
|
94
|
-
export type RecordingStartInput = z.infer<typeof RecordingStartInputSchema>;
|
|
95
|
-
export type RecordingOperationOutput = z.infer<
|
|
96
|
-
typeof RecordingOperationOutputSchema
|
|
97
|
-
>;
|
|
98
|
-
export type EmptyRecordingOperationInput = z.infer<
|
|
99
|
-
typeof EmptyRecordingOperationInputSchema
|
|
100
|
-
>;
|
|
101
|
-
|
|
102
|
-
export const recordingStartPolicy = {
|
|
103
|
-
cache: "none",
|
|
104
|
-
cancellable: false,
|
|
105
|
-
effect: "live-control",
|
|
106
|
-
maxDurationMs: 5 * 60_000,
|
|
107
|
-
maxFanOut: 0,
|
|
108
|
-
maxInputBytes: 32 * 1_024,
|
|
109
|
-
maxOutputBytes: 64 * 1_024,
|
|
110
|
-
preparation: [
|
|
111
|
-
"recording-metadata",
|
|
112
|
-
"screen-capture",
|
|
113
|
-
"camera",
|
|
114
|
-
"microphone",
|
|
115
|
-
"system-audio",
|
|
116
|
-
"typed-text",
|
|
117
|
-
"window-metadata",
|
|
118
|
-
],
|
|
119
|
-
resources: [{ amount: 1, resource: "capture-device" }],
|
|
120
|
-
resume: "non-resumable-live",
|
|
121
|
-
} as const satisfies OperationPolicy;
|
|
122
|
-
|
|
123
|
-
export const recordingTransitionPolicy = {
|
|
124
|
-
cache: "none",
|
|
125
|
-
cancellable: false,
|
|
126
|
-
effect: "live-control",
|
|
127
|
-
maxDurationMs: 5 * 60_000,
|
|
128
|
-
maxFanOut: 0,
|
|
129
|
-
maxInputBytes: 64,
|
|
130
|
-
maxOutputBytes: 64 * 1_024,
|
|
131
|
-
preparation: [],
|
|
132
|
-
resources: [{ amount: 1, resource: "capture-device" }],
|
|
133
|
-
resume: "non-resumable-live",
|
|
134
|
-
} as const satisfies OperationPolicy;
|
|
135
|
-
|
|
136
|
-
function requireRecordingController(
|
|
137
|
-
application: ApplicationContext,
|
|
138
|
-
): ApplicationRecordingController {
|
|
139
|
-
const controller = application.recordingController;
|
|
140
|
-
if (controller === undefined) {
|
|
141
|
-
throw new ApplicationError(
|
|
142
|
-
"unavailable",
|
|
143
|
-
"Recording controller is unavailable.",
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
return controller;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export function parseRecordingOperationOutput(
|
|
150
|
-
value: unknown,
|
|
151
|
-
): RecordingOperationOutput {
|
|
152
|
-
const parsed = ControllerRecordingSnapshotSchema.safeParse(value);
|
|
153
|
-
if (!parsed.success) {
|
|
154
|
-
throw new ApplicationError(
|
|
155
|
-
"invalid-data",
|
|
156
|
-
"Recording controller returned an invalid bounded snapshot.",
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
const snapshot = parsed.data;
|
|
160
|
-
return RecordingOperationOutputSchema.parse({
|
|
161
|
-
completedSegmentCount: snapshot.completedSegmentCount,
|
|
162
|
-
effectiveConfig: snapshot.effectiveConfig,
|
|
163
|
-
logicalTimeUs: snapshot.logicalTimeUs,
|
|
164
|
-
permissions: snapshot.permissions,
|
|
165
|
-
recordingId: snapshot.recordingId,
|
|
166
|
-
state: snapshot.state,
|
|
167
|
-
updatedAt: snapshot.updatedAt,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export async function executeRecordingControl(
|
|
172
|
-
context: OperationExecutionContext,
|
|
173
|
-
action: "pause" | "resume" | "start" | "stop",
|
|
174
|
-
options?: RecordingStartInput,
|
|
175
|
-
): Promise<RecordingOperationOutput> {
|
|
176
|
-
throwIfAborted(context.abortSignal);
|
|
177
|
-
const controller = requireRecordingController(context.application);
|
|
178
|
-
await context.workflow?.beforePublication();
|
|
179
|
-
const snapshot = options === undefined
|
|
180
|
-
? await controller.execute(action)
|
|
181
|
-
: await controller.execute(action, options);
|
|
182
|
-
return parseRecordingOperationOutput(snapshot);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export function summarizeRecordingControl(
|
|
186
|
-
kind: Extract<OperationKind, `recording.${string}`>,
|
|
187
|
-
output: RecordingOperationOutput,
|
|
188
|
-
): BoundedOperationSummary {
|
|
189
|
-
return {
|
|
190
|
-
fields: {
|
|
191
|
-
completedSegmentCount: output.completedSegmentCount,
|
|
192
|
-
logicalTimeUs: output.logicalTimeUs,
|
|
193
|
-
recordingId: output.recordingId,
|
|
194
|
-
state: output.state,
|
|
195
|
-
updatedAt: output.updatedAt,
|
|
196
|
-
},
|
|
197
|
-
kind,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
CapturePermissionsSchema,
|
|
5
|
-
IsoTimestampSchema,
|
|
6
|
-
MicrosecondsSchema,
|
|
7
|
-
RecordingIdSchema,
|
|
8
|
-
} from "../../../contracts";
|
|
9
|
-
import type { OperationDefinition } from "../../operation";
|
|
10
|
-
import {
|
|
11
|
-
executeRecordingControl,
|
|
12
|
-
MAX_RECORDING_OPERATION_DISPLAYS,
|
|
13
|
-
RecordingOperationOutputSchema,
|
|
14
|
-
type RecordingOperationOutput,
|
|
15
|
-
RecordingStartInputSchema,
|
|
16
|
-
type RecordingStartInput,
|
|
17
|
-
recordingStartPolicy,
|
|
18
|
-
summarizeRecordingControl,
|
|
19
|
-
} from "./shared";
|
|
20
|
-
|
|
21
|
-
export const RecordingStartOutputSchema = RecordingOperationOutputSchema;
|
|
22
|
-
export type RecordingStartOutput = RecordingOperationOutput;
|
|
23
|
-
|
|
24
|
-
const RecordingDisplaySelectionV1Schema = z.discriminatedUnion("kind", [
|
|
25
|
-
z.strictObject({ kind: z.literal("all-current") }),
|
|
26
|
-
z.strictObject({
|
|
27
|
-
displayIds: z.array(z.string().min(1).max(256))
|
|
28
|
-
.min(1)
|
|
29
|
-
.max(MAX_RECORDING_OPERATION_DISPLAYS)
|
|
30
|
-
.superRefine((displayIds, context) => {
|
|
31
|
-
if (new Set(displayIds).size !== displayIds.length) {
|
|
32
|
-
context.addIssue({
|
|
33
|
-
code: "custom",
|
|
34
|
-
message: "Explicit recording display IDs must be unique.",
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}),
|
|
38
|
-
kind: z.literal("explicit"),
|
|
39
|
-
}),
|
|
40
|
-
]);
|
|
41
|
-
|
|
42
|
-
export const RecordingStartInputV1Schema = z.strictObject({
|
|
43
|
-
displaySelection: RecordingDisplaySelectionV1Schema,
|
|
44
|
-
microphone: z.boolean(),
|
|
45
|
-
strictInputs: z.boolean(),
|
|
46
|
-
systemAudio: z.boolean(),
|
|
47
|
-
typedText: z.boolean(),
|
|
48
|
-
webcam: z.boolean(),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const EffectiveRecordingConfigV1Schema = z.strictObject({
|
|
52
|
-
...RecordingStartInputV1Schema.shape,
|
|
53
|
-
metadata: z.literal(true),
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
export const RecordingStartOutputV1Schema = z.strictObject({
|
|
57
|
-
completedSegmentCount: z.number().int().safe().nonnegative(),
|
|
58
|
-
effectiveConfig: EffectiveRecordingConfigV1Schema.nullable(),
|
|
59
|
-
logicalTimeUs: MicrosecondsSchema,
|
|
60
|
-
permissions: CapturePermissionsSchema.nullable(),
|
|
61
|
-
recordingId: RecordingIdSchema.nullable(),
|
|
62
|
-
state: z.enum(["idle", "recording", "paused"]),
|
|
63
|
-
updatedAt: IsoTimestampSchema.max(64),
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export type RecordingStartInputV1 = z.infer<
|
|
67
|
-
typeof RecordingStartInputV1Schema
|
|
68
|
-
>;
|
|
69
|
-
export type RecordingStartOutputV1 = z.infer<
|
|
70
|
-
typeof RecordingStartOutputV1Schema
|
|
71
|
-
>;
|
|
72
|
-
|
|
73
|
-
function upgradeRecordingStartInput(
|
|
74
|
-
input: RecordingStartInputV1,
|
|
75
|
-
): RecordingStartInput {
|
|
76
|
-
return RecordingStartInputSchema.parse({
|
|
77
|
-
camera: { kind: input.webcam ? "default" : "disabled" },
|
|
78
|
-
displays: input.displaySelection.kind === "all-current"
|
|
79
|
-
? { kind: "all" }
|
|
80
|
-
: {
|
|
81
|
-
displayIds: input.displaySelection.displayIds,
|
|
82
|
-
kind: "selected",
|
|
83
|
-
},
|
|
84
|
-
microphone: { kind: input.microphone ? "default" : "disabled" },
|
|
85
|
-
strictInputs: input.strictInputs,
|
|
86
|
-
systemAudio: input.systemAudio,
|
|
87
|
-
typedText: input.typedText,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function downgradeRecordingStartOutput(
|
|
92
|
-
output: RecordingStartOutput,
|
|
93
|
-
): RecordingStartOutputV1 {
|
|
94
|
-
const effectiveConfig = output.effectiveConfig === null
|
|
95
|
-
? null
|
|
96
|
-
: {
|
|
97
|
-
displaySelection: output.effectiveConfig.displays.kind === "all"
|
|
98
|
-
? { kind: "all-current" as const }
|
|
99
|
-
: {
|
|
100
|
-
displayIds: output.effectiveConfig.displays.displayIds,
|
|
101
|
-
kind: "explicit" as const,
|
|
102
|
-
},
|
|
103
|
-
metadata: true as const,
|
|
104
|
-
microphone: output.effectiveConfig.microphone.kind !== "disabled",
|
|
105
|
-
strictInputs: output.effectiveConfig.strictInputs,
|
|
106
|
-
systemAudio: output.effectiveConfig.systemAudio,
|
|
107
|
-
typedText: output.effectiveConfig.typedText,
|
|
108
|
-
webcam: output.effectiveConfig.camera.kind !== "disabled",
|
|
109
|
-
};
|
|
110
|
-
return RecordingStartOutputV1Schema.parse({
|
|
111
|
-
...output,
|
|
112
|
-
effectiveConfig,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export const recordingStartOperationDefinitionV1: OperationDefinition<
|
|
117
|
-
"recording.start",
|
|
118
|
-
RecordingStartInputV1,
|
|
119
|
-
RecordingStartOutputV1
|
|
120
|
-
> = {
|
|
121
|
-
inputSchema: RecordingStartInputV1Schema,
|
|
122
|
-
inputSchemaId: "slopcamera.operation.recording.start.input/v1",
|
|
123
|
-
kind: "recording.start",
|
|
124
|
-
lifecycle: {
|
|
125
|
-
kind: "live-control",
|
|
126
|
-
execute: async (context, input) => downgradeRecordingStartOutput(
|
|
127
|
-
await executeRecordingControl(
|
|
128
|
-
context,
|
|
129
|
-
"start",
|
|
130
|
-
upgradeRecordingStartInput(input),
|
|
131
|
-
),
|
|
132
|
-
),
|
|
133
|
-
},
|
|
134
|
-
outputSchema: RecordingStartOutputV1Schema,
|
|
135
|
-
outputSchemaId: "slopcamera.operation.recording.start.output/v1",
|
|
136
|
-
policy: recordingStartPolicy,
|
|
137
|
-
summarize: output => ({
|
|
138
|
-
fields: {
|
|
139
|
-
completedSegmentCount: output.completedSegmentCount,
|
|
140
|
-
logicalTimeUs: output.logicalTimeUs,
|
|
141
|
-
recordingId: output.recordingId,
|
|
142
|
-
state: output.state,
|
|
143
|
-
updatedAt: output.updatedAt,
|
|
144
|
-
},
|
|
145
|
-
kind: "recording.start",
|
|
146
|
-
}),
|
|
147
|
-
version: 1,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export const recordingStartOperationDefinition: OperationDefinition<
|
|
151
|
-
"recording.start",
|
|
152
|
-
RecordingStartInput,
|
|
153
|
-
RecordingStartOutput
|
|
154
|
-
> = {
|
|
155
|
-
inputSchema: RecordingStartInputSchema,
|
|
156
|
-
inputSchemaId: "slopcamera.operation.recording.start.input/v2",
|
|
157
|
-
kind: "recording.start",
|
|
158
|
-
lifecycle: {
|
|
159
|
-
kind: "live-control",
|
|
160
|
-
execute: async (context, input) => (
|
|
161
|
-
await executeRecordingControl(context, "start", input)
|
|
162
|
-
),
|
|
163
|
-
},
|
|
164
|
-
outputSchema: RecordingStartOutputSchema,
|
|
165
|
-
outputSchemaId: "slopcamera.operation.recording.start.output/v2",
|
|
166
|
-
policy: recordingStartPolicy,
|
|
167
|
-
summarize: output => summarizeRecordingControl("recording.start", output),
|
|
168
|
-
version: 2,
|
|
169
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { OperationDefinition } from "../../operation";
|
|
2
|
-
import {
|
|
3
|
-
EmptyRecordingOperationInputSchema,
|
|
4
|
-
type EmptyRecordingOperationInput,
|
|
5
|
-
executeRecordingControl,
|
|
6
|
-
RecordingOperationOutputSchema,
|
|
7
|
-
type RecordingOperationOutput,
|
|
8
|
-
recordingTransitionPolicy,
|
|
9
|
-
summarizeRecordingControl,
|
|
10
|
-
} from "./shared";
|
|
11
|
-
|
|
12
|
-
export const RecordingStopInputSchema = EmptyRecordingOperationInputSchema;
|
|
13
|
-
export const RecordingStopOutputSchema = RecordingOperationOutputSchema;
|
|
14
|
-
export type RecordingStopInput = EmptyRecordingOperationInput;
|
|
15
|
-
export type RecordingStopOutput = RecordingOperationOutput;
|
|
16
|
-
|
|
17
|
-
export const recordingStopOperationDefinition: OperationDefinition<
|
|
18
|
-
"recording.stop",
|
|
19
|
-
RecordingStopInput,
|
|
20
|
-
RecordingStopOutput
|
|
21
|
-
> = {
|
|
22
|
-
inputSchema: RecordingStopInputSchema,
|
|
23
|
-
inputSchemaId: "slopcamera.operation.recording.stop.input/v1",
|
|
24
|
-
kind: "recording.stop",
|
|
25
|
-
lifecycle: {
|
|
26
|
-
kind: "live-control",
|
|
27
|
-
execute: async context => await executeRecordingControl(context, "stop"),
|
|
28
|
-
},
|
|
29
|
-
outputSchema: RecordingStopOutputSchema,
|
|
30
|
-
outputSchemaId: "slopcamera.operation.recording.stop.output/v1",
|
|
31
|
-
policy: recordingTransitionPolicy,
|
|
32
|
-
summarize: output => summarizeRecordingControl("recording.stop", output),
|
|
33
|
-
version: 1,
|
|
34
|
-
};
|