@moondeck/station 1.0.0 → 1.0.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/db/migrations/0031_first_turn_receipts.sql +9 -0
- package/db/migrations/meta/_journal.json +7 -0
- package/db/schema.ts +21 -0
- package/images/standard/Dockerfile +6 -2
- package/images/standard/container/uai-create-node-data +6 -0
- package/images/standard/container/uai-repair-node-data.py +93 -0
- package/lib/agent-cli.ts +26 -5
- package/lib/browser-testing.ts +5 -0
- package/lib/container-runtime.ts +28 -11
- package/lib/env-schema.ts +70 -24
- package/lib/first-turn-receipts.ts +62 -0
- package/lib/machine-provider-local.ts +2 -0
- package/lib/node-state.ts +17 -0
- package/lib/orchestrator.ts +18 -31
- package/lib/preview-ports.ts +3 -0
- package/lib/preview-upstream.ts +61 -0
- package/lib/runtime-archive.ts +2 -0
- package/lib/task-environment/machine-task-up.ts +27 -0
- package/package.json +1 -1
- package/scripts/agent/task-up.sh +25 -15
- package/src/bridge-diagnostics.ts +39 -0
- package/src/cli.ts +6 -4
- package/src/enrollment-next-steps.ts +24 -0
- package/src/index.ts +31 -13
- package/src/main.ts +46 -10
- package/src/preview-upstream.ts +41 -0
- package/src/protocol.ts +11 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Optional preview behavior, negotiated per live Station connection. */
|
|
2
|
+
export const PREVIEW_UPSTREAM_PROTOCOL_FEATURE = "preview-upstream-v1";
|
|
3
|
+
|
|
4
|
+
export interface PreviewUpstream {
|
|
5
|
+
upstreamHost?: string;
|
|
6
|
+
upstreamTls?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** DNS spelling only. URL parsing here detects numeric/hex/octal IP aliases;
|
|
10
|
+
* it never resolves a name. No URL, authority, port or header syntax is allowed. */
|
|
11
|
+
export function isPreviewUpstreamHost(value: unknown): value is string {
|
|
12
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 253) return false;
|
|
13
|
+
if (!value.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(label))) return false;
|
|
14
|
+
try {
|
|
15
|
+
return !/^\d+\.\d+\.\d+\.\d+$/.test(new URL(`http://${value}`).hostname);
|
|
16
|
+
} catch { return false; }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function hasPreviewUpstream(value: PreviewUpstream): boolean {
|
|
20
|
+
return value.upstreamHost !== undefined || value.upstreamTls === true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Read only these fields from a frame or declaration; reject malformed values. */
|
|
24
|
+
export function parsePreviewUpstream(value: unknown): PreviewUpstream | null {
|
|
25
|
+
if (value === undefined) return {};
|
|
26
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
27
|
+
const { upstreamHost, upstreamTls } = value as Record<string, unknown>;
|
|
28
|
+
if (upstreamHost !== undefined && !isPreviewUpstreamHost(upstreamHost)) return null;
|
|
29
|
+
if (upstreamTls !== undefined && typeof upstreamTls !== "boolean") return null;
|
|
30
|
+
return {
|
|
31
|
+
...(typeof upstreamHost === "string" ? { upstreamHost: upstreamHost.toLowerCase() } : {}),
|
|
32
|
+
...(typeof upstreamTls === "boolean" ? { upstreamTls } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function tunnelPreviewUpstream(frame: { target: string; containerPort?: number } & PreviewUpstream): PreviewUpstream | null {
|
|
37
|
+
const settings = parsePreviewUpstream(frame);
|
|
38
|
+
if (!settings) return null;
|
|
39
|
+
if (hasPreviewUpstream(settings) && (frame.target !== "preview" || !Number.isInteger(frame.containerPort) || frame.containerPort! < 1 || frame.containerPort! > 65535)) return null;
|
|
40
|
+
return settings;
|
|
41
|
+
}
|
package/src/protocol.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from "./custom-connections";
|
|
2
|
+
export * from "./preview-upstream";
|
|
3
|
+
import type { PreviewUpstream } from "./preview-upstream";
|
|
2
4
|
import type { AccountBinding, EngineConnectCustomDiscoverFrame, EngineConnectCustomDiscoveredFrame, EngineConnectCustomSaveFrame, EngineConnectCustomManualSaveFrame, EngineConnectCustomSavedFrame, OpenRouterBudgetFrame } from "./custom-connections";
|
|
3
5
|
import type { TaskSecretApplied, TaskSecretStagingPut, TaskSecretStagingAck } from "./task-secrets";
|
|
4
6
|
import { isNeverProxiedDomain } from "./never-proxied-domains";
|
|
@@ -101,6 +103,8 @@ export type HostCommandResult<T> =
|
|
|
101
103
|
|
|
102
104
|
/** Capability ids shared by host advertisement and fail-closed cloud gates. */
|
|
103
105
|
export const ASSIGNMENT_EVIDENCE_PROTOCOL_FEATURE = "assignment-evidence-v1";
|
|
106
|
+
/** Hosts that accept at most one delivery per first-turn id (6th channelDeliver arg). */
|
|
107
|
+
export const FIRST_TURN_DEDUP_PROTOCOL_FEATURE = "first-turn-dedup-v1";
|
|
104
108
|
export const LEAD_EVIDENCE_PROTOCOL_FEATURE = "lead-evidence-v1";
|
|
105
109
|
export const TRANSCRIPT_TARGETS_PROTOCOL_FEATURE = "transcript-targets-v1";
|
|
106
110
|
export const SECRETARY_TYPED_DISPATCH_PROTOCOL_FEATURE =
|
|
@@ -305,7 +309,7 @@ export const INITIAL_PROJECT_ENV_POLICY_EPOCH = 1;
|
|
|
305
309
|
* The wire guard accepts every historical positive epoch through this value,
|
|
306
310
|
* but rejects a future epoch until this peer knows how to interpret it.
|
|
307
311
|
*/
|
|
308
|
-
export const CURRENT_PROJECT_ENV_PARSER_EPOCH =
|
|
312
|
+
export const CURRENT_PROJECT_ENV_PARSER_EPOCH = 3;
|
|
309
313
|
|
|
310
314
|
export const PROJECT_ENV_UNSUPPORTED_REASON_CODES = [
|
|
311
315
|
"malformed",
|
|
@@ -4810,6 +4814,9 @@ export interface HostCommands {
|
|
|
4810
4814
|
* from an older cloud, which the host reads as "not a human turn". */
|
|
4811
4815
|
origin?: DeliveryOrigin,
|
|
4812
4816
|
assignment?: AssignmentDelivery,
|
|
4817
|
+
/** `first-turn-dedup-v1`: stable id of a first-turn delivery. A repeat of
|
|
4818
|
+
* an accepted id is acknowledged without queueing another turn. */
|
|
4819
|
+
firstTurnId?: string,
|
|
4813
4820
|
): Promise<HostCommandResult<void>>;
|
|
4814
4821
|
channelResolvePermission(
|
|
4815
4822
|
ctx: CommandContext,
|
|
@@ -4830,6 +4837,7 @@ export interface HostCommands {
|
|
|
4830
4837
|
taskId: string,
|
|
4831
4838
|
name: string,
|
|
4832
4839
|
containerPort: number,
|
|
4840
|
+
upstream?: PreviewUpstream,
|
|
4833
4841
|
): Promise<HostCommandResult<{ hostPort: number | null }>>;
|
|
4834
4842
|
/** ADR-116: remove a labeled engine account by id. Refuses `default:*`
|
|
4835
4843
|
* exactly like the local API; re-advertises capabilities on success. */
|
|
@@ -4992,6 +5000,8 @@ export type CloudToHost =
|
|
|
4992
5000
|
// proxies to <container-ip>:<containerPort> over the Docker network.
|
|
4993
5001
|
// Absent for the editor target (which uses the published codeServerPort).
|
|
4994
5002
|
containerPort?: number;
|
|
5003
|
+
upstreamHost?: string;
|
|
5004
|
+
upstreamTls?: boolean;
|
|
4995
5005
|
reqLine: TunnelReqLine;
|
|
4996
5006
|
upgrade: boolean;
|
|
4997
5007
|
}
|