@tomflow/proflow-platform-host 0.1.5 → 0.1.7

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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @tomflow/proflow-platform-host
2
+
3
+ ## 0.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Align all Modules to the seven-command setup contract with executable package-owned setup guidance and full Platform setup aggregation.
package/DOCS.md ADDED
@@ -0,0 +1,30 @@
1
+ # @tomflow/proflow-platform-host — Module Docs
2
+
3
+ Module ref: `platform-host`
4
+ Domain: `platform-architecture`
5
+ Kind: `service`
6
+
7
+ Provides the ProFlow local application composition root that binds Task, Agent, Execution and Model owner transports.
8
+
9
+ ## Standard management surface
10
+
11
+ `install / uninstall / status / setup / docs / start / stop`
12
+
13
+ ## Provides
14
+
15
+ - `platform-host` `1.0.0`
16
+
17
+ ## Requires
18
+
19
+ - `task-orchestration` `>=1.0.0 <2.0.0`
20
+ - `agent-runtime` `>=1.0.0 <2.0.0`
21
+ - `execution` `>=1.0.0 <2.0.0`
22
+ - `model-inference` `>=1.0.0 <2.0.0`
23
+
24
+ ## Public setup inputs
25
+
26
+ - None. Deterministic/private values and cross-Module shared facts are not public configuration.
27
+
28
+ ## Ownership boundary
29
+
30
+ Module business APIs and any module-specific extra commands remain package-owned. Platform does not proxy or interpret them. Current human/external preparation is documented in `SETUP.md`.
package/SETUP.md ADDED
@@ -0,0 +1,19 @@
1
+ # @tomflow/proflow-platform-host — Module Setup
2
+
3
+ ## Goal
4
+
5
+ Reach `setupStatus=READY` without user configuration.
6
+
7
+ ## Step 1 — Complete machine-owned preparation
8
+
9
+ **Type:** automatic
10
+ **Executable:** `platform install`
11
+ **What happens:** No user input is required. Local endpoints, stateRoot and credential files are deterministic. Execution/Model facts must come from producer-owned shared facts; if absent this Module reports FAILED rather than asking the user to copy them.
12
+
13
+ ## Step 2 — Re-observe dependency and setup state
14
+
15
+ **Type:** automatic verification
16
+ **Verify:** `platform status`
17
+ **Success condition:** `platform-host.setupStatus=READY`.
18
+
19
+ There is no human setup action. A missing machine-owned artifact or producer-owned dependency is a `FAILED` condition to fix in the owning package/dependency; it must never be converted into a request for path/token/endpoint input.
@@ -1,362 +1,138 @@
1
- type PlatformHostService = {
2
- start(): Promise<{
3
- host: string;
4
- port: number;
5
- }>;
6
- stop(): Promise<void>;
7
- restart(): Promise<{
8
- host: string;
9
- port: number;
10
- }>;
11
- status(): Promise<{
12
- readiness: "READY" | "NOT_READY";
13
- }>;
14
- };
15
- export declare function createBehaviorAdapter(service?: PlatformHostService, config?: Record<string, string>, configValid?: boolean): {
16
- describe: () => {
17
- result: {
18
- readonly contract: "deployment.result.v1";
19
- readonly ok: true;
20
- readonly status: "SUCCEEDED";
21
- readonly moduleRef: "platform-host";
22
- readonly moduleVersion: "0.1.5";
23
- };
24
- observedEffects: never[];
25
- };
26
- preflight: () => {
27
- result: {
28
- readonly contract: "deployment.result.v1";
29
- readonly ok: true;
30
- readonly status: "SUCCEEDED";
31
- readonly moduleRef: "platform-host";
32
- readonly moduleVersion: "0.1.5";
33
- };
34
- observedEffects: never[];
35
- };
36
- status: () => Promise<{
1
+ import { type ModuleCommandContext } from "@tomflow/proflow-module-contract";
2
+ export declare const behaviorAdapter: {
3
+ readonly install: (context: ModuleCommandContext) => Promise<{
37
4
  result: {
38
5
  contract: "deployment.result.v1";
39
6
  ok: true;
40
7
  status: "SUCCEEDED";
41
8
  moduleRef: "platform-host";
42
- moduleVersion: "0.1.5";
9
+ moduleVersion: "0.1.7";
43
10
  data: {
44
- configStatus: "INCOMPLETE" | "INVALID" | "READY";
45
- missingConfig?: string[] | undefined;
46
- runtimeStatus: "FAILED" | "RUNNING" | "STOPPED" | "UNKNOWN";
47
- };
48
- };
49
- observedEffects: never[];
50
- }>;
51
- verify: () => Promise<{
52
- result: {
53
- contract: "deployment.result.v1";
54
- ok: true;
55
- status: "SUCCEEDED";
56
- moduleRef: "platform-host";
57
- moduleVersion: "0.1.5";
58
- checks: {
59
- id: string;
60
- status: "FAIL" | "PASS";
61
- message: string;
62
- }[];
63
- } | {
64
- contract: "deployment.result.v1";
65
- moduleRef: "platform-host";
66
- moduleVersion: "0.1.5";
67
- ok: false;
68
- status: "ACTION_REQUIRED";
69
- actionRequired: {
70
- readonly action: "compose-platform-host";
71
- readonly description: "Provide validated Host configuration and owner transports";
72
- };
73
- checks: {
74
- id: string;
75
- status: "FAIL" | "PASS";
76
- message: string;
77
- }[];
78
- } | {
79
- contract: "deployment.result.v1";
80
- moduleRef: "platform-host";
81
- moduleVersion: "0.1.5";
82
- ok: false;
83
- status: "ACTION_REQUIRED";
84
- actionRequired: {
85
- action: string;
86
- description: string;
11
+ endpoint: string;
12
+ stateRoot: string;
13
+ identityTokenFile: string;
14
+ taskApplicationTokenFile: string;
15
+ approvalApplicationTokenFile: string;
16
+ gatewayTransportCredentialFile: string;
87
17
  };
88
- checks: {
89
- id: string;
90
- status: "FAIL" | "PASS";
91
- message: string;
92
- }[];
93
18
  };
94
19
  observedEffects: never[];
95
20
  }>;
96
- doctor: () => {
21
+ readonly uninstall: (context: ModuleCommandContext) => Promise<{
97
22
  result: {
98
23
  readonly contract: "deployment.result.v1";
99
24
  readonly ok: true;
100
25
  readonly status: "SUCCEEDED";
101
26
  readonly moduleRef: "platform-host";
102
- readonly moduleVersion: "0.1.5";
27
+ readonly moduleVersion: "0.1.7";
103
28
  };
104
- observedEffects: never[];
105
- };
106
- start: () => Promise<{
29
+ observedEffects: string[];
30
+ }>;
31
+ readonly status: (context: ModuleCommandContext) => Promise<{
107
32
  result: {
108
- readonly contract: "deployment.result.v1";
109
- readonly moduleRef: "platform-host";
110
- readonly moduleVersion: "0.1.5";
111
- readonly ok: false;
112
- readonly status: "ACTION_REQUIRED";
113
- readonly actionRequired: {
114
- readonly action: "compose-platform-host";
115
- readonly description: "Provide validated Host configuration and owner transports";
116
- };
117
- } | {
118
33
  contract: "deployment.result.v1";
119
34
  ok: true;
120
35
  status: "SUCCEEDED";
121
36
  moduleRef: "platform-host";
122
- moduleVersion: "0.1.5";
37
+ moduleVersion: "0.1.7";
123
38
  data: {
124
- host: string;
125
- port: number;
39
+ setupStatus: "FAILED" | "READY";
40
+ runtimeStatus: "RUNNING" | "STOPPED";
126
41
  };
127
42
  };
128
- observedEffects: string[];
43
+ observedEffects: never[];
129
44
  }>;
130
- stop: () => Promise<{
45
+ readonly setup: (context: ModuleCommandContext) => Promise<{
131
46
  result: {
132
47
  readonly contract: "deployment.result.v1";
133
48
  readonly ok: true;
134
49
  readonly status: "SUCCEEDED";
135
50
  readonly moduleRef: "platform-host";
136
- readonly moduleVersion: "0.1.5";
51
+ readonly moduleVersion: "0.1.7";
137
52
  } | {
138
- readonly contract: "deployment.result.v1";
139
- readonly moduleRef: "platform-host";
140
- readonly moduleVersion: "0.1.5";
141
- readonly ok: false;
142
- readonly status: "ACTION_REQUIRED";
143
- readonly actionRequired: {
144
- readonly action: "compose-platform-host";
145
- readonly description: "Provide validated Host configuration and owner transports";
53
+ contract: "deployment.result.v1";
54
+ moduleRef: "platform-host";
55
+ moduleVersion: "0.1.7";
56
+ ok: false;
57
+ status: "FAILED";
58
+ error: {
59
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
60
+ message: string;
61
+ retryable: boolean;
146
62
  };
147
63
  };
148
- observedEffects: string[];
64
+ observedEffects: never[];
149
65
  }>;
150
- restart: () => Promise<{
66
+ readonly docs: (_context: ModuleCommandContext) => Promise<{
151
67
  result: {
152
- readonly contract: "deployment.result.v1";
153
- readonly moduleRef: "platform-host";
154
- readonly moduleVersion: "0.1.5";
155
- readonly ok: false;
156
- readonly status: "ACTION_REQUIRED";
157
- readonly actionRequired: {
158
- readonly action: "compose-platform-host";
159
- readonly description: "Provide validated Host configuration and owner transports";
160
- };
161
- } | {
162
68
  contract: "deployment.result.v1";
163
69
  ok: true;
164
70
  status: "SUCCEEDED";
165
71
  moduleRef: "platform-host";
166
- moduleVersion: "0.1.5";
72
+ moduleVersion: "0.1.7";
167
73
  data: {
168
- host: string;
169
- port: number;
74
+ docs: string;
75
+ setup: string;
170
76
  };
171
77
  };
172
- observedEffects: string[];
173
- }>;
174
- uninstall: () => Promise<{
175
- result: {
176
- readonly contract: "deployment.result.v1";
177
- readonly ok: true;
178
- readonly status: "SUCCEEDED";
179
- readonly moduleRef: "platform-host";
180
- readonly moduleVersion: "0.1.5";
181
- };
182
- observedEffects: string[];
183
- }>;
184
- };
185
- export declare const behaviorAdapter: {
186
- describe: () => {
187
- result: {
188
- readonly contract: "deployment.result.v1";
189
- readonly ok: true;
190
- readonly status: "SUCCEEDED";
191
- readonly moduleRef: "platform-host";
192
- readonly moduleVersion: "0.1.5";
193
- };
194
78
  observedEffects: never[];
195
- };
196
- preflight: () => {
197
- result: {
198
- readonly contract: "deployment.result.v1";
199
- readonly ok: true;
200
- readonly status: "SUCCEEDED";
201
- readonly moduleRef: "platform-host";
202
- readonly moduleVersion: "0.1.5";
203
- };
204
- observedEffects: never[];
205
- };
206
- status: () => Promise<{
79
+ }>;
80
+ readonly start: (context: ModuleCommandContext) => Promise<{
207
81
  result: {
208
82
  contract: "deployment.result.v1";
209
83
  ok: true;
210
84
  status: "SUCCEEDED";
211
85
  moduleRef: "platform-host";
212
- moduleVersion: "0.1.5";
86
+ moduleVersion: "0.1.7";
213
87
  data: {
214
- configStatus: "INCOMPLETE" | "INVALID" | "READY";
215
- missingConfig?: string[] | undefined;
216
- runtimeStatus: "FAILED" | "RUNNING" | "STOPPED" | "UNKNOWN";
88
+ host: string;
89
+ port: number;
217
90
  };
218
91
  };
219
- observedEffects: never[];
220
- }>;
221
- verify: () => Promise<{
92
+ observedEffects: string[];
93
+ } | {
222
94
  result: {
223
- contract: "deployment.result.v1";
224
- ok: true;
225
- status: "SUCCEEDED";
226
- moduleRef: "platform-host";
227
- moduleVersion: "0.1.5";
228
- checks: {
229
- id: string;
230
- status: "FAIL" | "PASS";
231
- message: string;
232
- }[];
233
- } | {
234
95
  contract: "deployment.result.v1";
235
96
  moduleRef: "platform-host";
236
- moduleVersion: "0.1.5";
97
+ moduleVersion: "0.1.7";
237
98
  ok: false;
238
- status: "ACTION_REQUIRED";
239
- actionRequired: {
240
- readonly action: "compose-platform-host";
241
- readonly description: "Provide validated Host configuration and owner transports";
242
- };
243
- checks: {
244
- id: string;
245
- status: "FAIL" | "PASS";
99
+ status: "FAILED";
100
+ error: {
101
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
246
102
  message: string;
247
- }[];
248
- } | {
249
- contract: "deployment.result.v1";
250
- moduleRef: "platform-host";
251
- moduleVersion: "0.1.5";
252
- ok: false;
253
- status: "ACTION_REQUIRED";
254
- actionRequired: {
255
- action: string;
256
- description: string;
103
+ retryable: boolean;
257
104
  };
258
- checks: {
259
- id: string;
260
- status: "FAIL" | "PASS";
261
- message: string;
262
- }[];
263
105
  };
264
106
  observedEffects: never[];
265
107
  }>;
266
- doctor: () => {
108
+ readonly stop: (context: ModuleCommandContext) => Promise<{
267
109
  result: {
268
110
  readonly contract: "deployment.result.v1";
269
111
  readonly ok: true;
270
112
  readonly status: "SUCCEEDED";
271
113
  readonly moduleRef: "platform-host";
272
- readonly moduleVersion: "0.1.5";
273
- };
274
- observedEffects: never[];
275
- };
276
- start: () => Promise<{
277
- result: {
278
- readonly contract: "deployment.result.v1";
279
- readonly moduleRef: "platform-host";
280
- readonly moduleVersion: "0.1.5";
281
- readonly ok: false;
282
- readonly status: "ACTION_REQUIRED";
283
- readonly actionRequired: {
284
- readonly action: "compose-platform-host";
285
- readonly description: "Provide validated Host configuration and owner transports";
286
- };
287
- } | {
288
- contract: "deployment.result.v1";
289
- ok: true;
290
- status: "SUCCEEDED";
291
- moduleRef: "platform-host";
292
- moduleVersion: "0.1.5";
293
- data: {
294
- host: string;
295
- port: number;
296
- };
114
+ readonly moduleVersion: "0.1.7";
297
115
  };
298
116
  observedEffects: string[];
299
- }>;
300
- stop: () => Promise<{
117
+ } | {
301
118
  result: {
302
119
  readonly contract: "deployment.result.v1";
303
120
  readonly ok: true;
304
121
  readonly status: "SUCCEEDED";
305
122
  readonly moduleRef: "platform-host";
306
- readonly moduleVersion: "0.1.5";
307
- } | {
308
- readonly contract: "deployment.result.v1";
309
- readonly moduleRef: "platform-host";
310
- readonly moduleVersion: "0.1.5";
311
- readonly ok: false;
312
- readonly status: "ACTION_REQUIRED";
313
- readonly actionRequired: {
314
- readonly action: "compose-platform-host";
315
- readonly description: "Provide validated Host configuration and owner transports";
316
- };
317
- };
318
- observedEffects: string[];
319
- }>;
320
- restart: () => Promise<{
321
- result: {
322
- readonly contract: "deployment.result.v1";
323
- readonly moduleRef: "platform-host";
324
- readonly moduleVersion: "0.1.5";
325
- readonly ok: false;
326
- readonly status: "ACTION_REQUIRED";
327
- readonly actionRequired: {
328
- readonly action: "compose-platform-host";
329
- readonly description: "Provide validated Host configuration and owner transports";
330
- };
123
+ readonly moduleVersion: "0.1.7";
331
124
  } | {
332
125
  contract: "deployment.result.v1";
333
- ok: true;
334
- status: "SUCCEEDED";
335
126
  moduleRef: "platform-host";
336
- moduleVersion: "0.1.5";
337
- data: {
338
- host: string;
339
- port: number;
127
+ moduleVersion: "0.1.7";
128
+ ok: false;
129
+ status: "FAILED";
130
+ error: {
131
+ code: "SETUP_FAILED" | "START_FAILED" | "STOP_FAILED";
132
+ message: string;
133
+ retryable: boolean;
340
134
  };
341
135
  };
342
- observedEffects: string[];
343
- }>;
344
- uninstall: () => Promise<{
345
- result: {
346
- readonly contract: "deployment.result.v1";
347
- readonly ok: true;
348
- readonly status: "SUCCEEDED";
349
- readonly moduleRef: "platform-host";
350
- readonly moduleVersion: "0.1.5";
351
- };
352
- observedEffects: string[];
136
+ observedEffects: never[];
353
137
  }>;
354
138
  };
355
- export declare function createProductionBinding(input: {
356
- moduleRef: string;
357
- config: Record<string, string>;
358
- configByModuleRef: ReadonlyMap<string, Record<string, string>>;
359
- }): Promise<{
360
- behaviorAdapter: Record<string, unknown>;
361
- }>;
362
- export {};
@@ -1,5 +1,10 @@
1
- import { observeDeclaredModuleStatus } from "@tomflow/proflow-module-contract";
1
+ import { randomBytes } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { deterministicLoopbackPort, ensureModuleSecretFile, readModuleSharedFacts, writeModuleSharedFacts, } from "@tomflow/proflow-module-contract";
2
6
  import { descriptor } from "./descriptor.js";
7
+ const services = new Map();
3
8
  const base = {
4
9
  contract: "deployment.result.v1",
5
10
  ok: true,
@@ -7,155 +12,168 @@ const base = {
7
12
  moduleRef: descriptor.moduleRef,
8
13
  moduleVersion: descriptor.moduleVersion,
9
14
  };
10
- const unbound = {
15
+ const key = (context) => resolve(context.workspaceRoot);
16
+ const stateRoot = (context) => join(key(context), ".proflow");
17
+ const factString = (facts, name) => (typeof facts?.[name] === "string" ? String(facts[name]) : undefined);
18
+ async function ensureSecret(path) {
19
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
20
+ if (!existsSync(path))
21
+ await writeFile(path, `${randomBytes(32).toString("base64url")}\n`, {
22
+ mode: 0o600,
23
+ });
24
+ await chmod(path, 0o600);
25
+ const value = (await readFile(path, "utf8")).trim();
26
+ if (value.length < 32)
27
+ throw new Error(`invalid private credential ${path}`);
28
+ return path;
29
+ }
30
+ async function ownFacts(context) {
31
+ const root = stateRoot(context);
32
+ const endpoint = `http://127.0.0.1:${deterministicLoopbackPort(context, descriptor.moduleRef)}`;
33
+ const identityTokenFile = await ensureSecret(join(root, "execution", "secrets", "execution-identity.token"));
34
+ const taskApplicationTokenFile = await ensureSecret(join(root, "browser", "secrets", "task-application.token"));
35
+ const approvalApplicationTokenFile = await ensureSecret(join(root, "browser", "secrets", "approval-application.token"));
36
+ const gatewayTransportCredentialFile = await ensureModuleSecretFile(context, descriptor.moduleRef, "gateway-transport");
37
+ const facts = {
38
+ endpoint,
39
+ stateRoot: root,
40
+ identityTokenFile,
41
+ taskApplicationTokenFile,
42
+ approvalApplicationTokenFile,
43
+ gatewayTransportCredentialFile,
44
+ };
45
+ await writeModuleSharedFacts(context, descriptor.moduleRef, facts);
46
+ return facts;
47
+ }
48
+ async function dependencies(context) {
49
+ const execution = await readModuleSharedFacts(context, "execution-runtime");
50
+ const model = await readModuleSharedFacts(context, "model-runtime");
51
+ const executionBaseUrl = factString(execution, "endpoint");
52
+ const executionTransportCredentialFile = factString(execution, "transportCredentialFile");
53
+ const modelBaseUrl = factString(model, "endpoint");
54
+ const modelTransportCredentialFile = factString(model, "transportCredentialFile");
55
+ return executionBaseUrl &&
56
+ executionTransportCredentialFile &&
57
+ modelBaseUrl &&
58
+ modelTransportCredentialFile
59
+ ? {
60
+ executionBaseUrl,
61
+ executionTransportCredentialFile,
62
+ modelBaseUrl,
63
+ modelTransportCredentialFile,
64
+ }
65
+ : undefined;
66
+ }
67
+ async function running(context) {
68
+ const { endpoint } = await ownFacts(context);
69
+ try {
70
+ return (await fetch(`${endpoint}/ready`, { signal: AbortSignal.timeout(500) })).ok;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ async function compose(context) {
77
+ const own = await ownFacts(context);
78
+ const deps = await dependencies(context);
79
+ if (!deps)
80
+ throw new Error("required Execution/Model shared facts are unavailable");
81
+ const { createPlatformHost, parsePlatformHostConfig } = await import("../src/index.js");
82
+ const url = new URL(own.endpoint);
83
+ const host = createPlatformHost({
84
+ config: parsePlatformHostConfig({
85
+ stateRoot: own.stateRoot,
86
+ workspaceRoot: key(context),
87
+ host: url.hostname,
88
+ port: Number(url.port),
89
+ executionBaseUrl: deps.executionBaseUrl,
90
+ executionTransportCredentialFile: deps.executionTransportCredentialFile,
91
+ modelBaseUrl: deps.modelBaseUrl,
92
+ modelTransportCredentialFile: deps.modelTransportCredentialFile,
93
+ gatewayTransportCredentialFile: own.gatewayTransportCredentialFile,
94
+ roles: [],
95
+ }),
96
+ });
97
+ return { start: () => host.start(), stop: () => host.stop() };
98
+ }
99
+ const failed = (code, message) => ({
11
100
  ...base,
12
101
  ok: false,
13
- status: "ACTION_REQUIRED",
14
- actionRequired: {
15
- action: "compose-platform-host",
16
- description: "Provide validated Host configuration and owner transports",
102
+ status: "FAILED",
103
+ error: { code, message, retryable: true },
104
+ });
105
+ export const behaviorAdapter = {
106
+ install: async (context) => ({
107
+ result: { ...base, data: await ownFacts(context) },
108
+ observedEffects: [],
109
+ }),
110
+ uninstall: async (context) => {
111
+ const service = services.get(key(context));
112
+ if (service) {
113
+ await service.stop();
114
+ services.delete(key(context));
115
+ }
116
+ return {
117
+ result: base,
118
+ observedEffects: service ? ["Manage the platform-host process"] : [],
119
+ };
17
120
  },
18
- };
19
- export function createBehaviorAdapter(service, config, configValid = true) {
20
- return {
21
- describe: () => ({ result: base, observedEffects: [] }),
22
- preflight: () => ({ result: base, observedEffects: [] }),
23
- status: async () => {
24
- const status = service ? await service.status() : undefined;
25
- const ready = status?.readiness === "READY";
26
- const data = observeDeclaredModuleStatus(descriptor, config, ready ? "RUNNING" : service ? "FAILED" : "UNKNOWN", configValid);
121
+ status: async (context) => ({
122
+ result: {
123
+ ...base,
124
+ data: {
125
+ setupStatus: (await dependencies(context))
126
+ ? "READY"
127
+ : "FAILED",
128
+ runtimeStatus: (await running(context))
129
+ ? "RUNNING"
130
+ : "STOPPED",
131
+ },
132
+ },
133
+ observedEffects: [],
134
+ }),
135
+ setup: async (context) => ({
136
+ result: (await dependencies(context))
137
+ ? base
138
+ : failed("SETUP_FAILED", "required Execution/Model producer shared facts are unavailable"),
139
+ observedEffects: [],
140
+ }),
141
+ docs: async (_context) => ({
142
+ result: { ...base, data: { docs: "DOCS.md", setup: "SETUP.md" } },
143
+ observedEffects: [],
144
+ }),
145
+ start: async (context) => {
146
+ try {
147
+ const service = await compose(context);
148
+ const data = await service.start();
149
+ services.set(key(context), service);
27
150
  return {
28
151
  result: { ...base, data },
29
- observedEffects: [],
152
+ observedEffects: ["Manage the platform-host process"],
30
153
  };
31
- },
32
- verify: async () => {
33
- const status = service ? await service.status() : undefined;
34
- const ready = status?.readiness === "READY";
154
+ }
155
+ catch (error) {
35
156
  return {
36
- result: {
37
- ...(service && ready
38
- ? base
39
- : service
40
- ? {
41
- ...base,
42
- ok: false,
43
- status: "ACTION_REQUIRED",
44
- actionRequired: {
45
- action: "repair-platform-host",
46
- description: "Platform Host is not READY",
47
- },
48
- }
49
- : unbound),
50
- checks: [
51
- {
52
- id: "platform-host-readiness",
53
- status: ready ? "PASS" : "FAIL",
54
- message: service
55
- ? `Platform Host readiness is ${status?.readiness ?? "NOT_READY"}`
56
- : "No configured Host process is bound",
57
- },
58
- ],
59
- },
157
+ result: failed("START_FAILED", error instanceof Error ? error.message : "platform-host start failed"),
60
158
  observedEffects: [],
61
159
  };
62
- },
63
- doctor: () => ({ result: base, observedEffects: [] }),
64
- start: async () => ({
65
- result: service ? { ...base, data: await service.start() } : unbound,
66
- observedEffects: service ? ["Manage the platform-host process"] : [],
67
- }),
68
- stop: async () => {
69
- if (service)
70
- await service.stop();
71
- return {
72
- result: service ? base : unbound,
73
- observedEffects: service ? ["Manage the platform-host process"] : [],
74
- };
75
- },
76
- restart: async () => ({
77
- result: service ? { ...base, data: await service.restart() } : unbound,
78
- observedEffects: service ? ["Manage the platform-host process"] : [],
79
- }),
80
- uninstall: async () => {
81
- if (service)
82
- await service.stop();
160
+ }
161
+ },
162
+ stop: async (context) => {
163
+ const service = services.get(key(context));
164
+ if (service) {
165
+ await service.stop();
166
+ services.delete(key(context));
83
167
  return {
84
- // Uninstall is idempotent: an unbound service means there is no
85
- // process to stop before package removal. Runtime readiness still
86
- // fails closed in status/start/verify.
87
168
  result: base,
88
- observedEffects: service ? ["Manage the platform-host process"] : [],
169
+ observedEffects: ["Manage the platform-host process"],
89
170
  };
90
- },
91
- };
92
- }
93
- export const behaviorAdapter = createBehaviorAdapter();
94
- const REQUIRED_CONFIG = [
95
- "stateRoot",
96
- "workspaceRoot",
97
- "gatewayTransportCredentialFile",
98
- "executionBaseUrl",
99
- "executionTransportCredentialFile",
100
- "modelBaseUrl",
101
- "modelTransportCredentialFile",
102
- ];
103
- // Binds the real Host process only when materialized owner config and required
104
- // dependency composition are available. Unbound bindings still carry owner
105
- // config so status remains authoritative. The heavy src import is deferred
106
- // until a real binding is requested.
107
- export async function createProductionBinding(input) {
108
- const config = input.config;
109
- const unboundBinding = (configValid = true) => ({
110
- behaviorAdapter: createBehaviorAdapter(undefined, config, configValid),
111
- });
112
- if (!REQUIRED_CONFIG.every((key) => config[key] !== undefined))
113
- return unboundBinding();
114
- // The Platform Host's public loopback endpoint is already a cross-module
115
- // contract: Execution calls it through identity.endpoint. Reuse that
116
- // materialized endpoint as the listener instead of binding an ephemeral port
117
- // that no dependent module could discover after `start`.
118
- const executionRuntime = input.configByModuleRef.get("execution-runtime");
119
- const advertised = executionRuntime?.["identity.endpoint"];
120
- if (!advertised)
121
- return unboundBinding();
122
- let listener;
123
- try {
124
- listener = new URL(advertised);
125
- }
126
- catch {
127
- return unboundBinding();
128
- }
129
- if (listener.protocol !== "http:" || listener.pathname !== "/")
130
- return unboundBinding();
131
- const port = listener.port === "" ? 80 : Number(listener.port);
132
- if (!Number.isInteger(port) || port <= 0 || port > 65_535)
133
- return unboundBinding();
134
- const { createPlatformHost, parsePlatformHostConfig } = await import("../src/index.js");
135
- let hostConfig;
136
- try {
137
- hostConfig = parsePlatformHostConfig({
138
- stateRoot: config.stateRoot,
139
- workspaceRoot: config.workspaceRoot,
140
- host: listener.hostname,
141
- port,
142
- executionBaseUrl: config.executionBaseUrl,
143
- executionTransportCredentialFile: config.executionTransportCredentialFile,
144
- modelBaseUrl: config.modelBaseUrl,
145
- modelTransportCredentialFile: config.modelTransportCredentialFile,
146
- gatewayTransportCredentialFile: config.gatewayTransportCredentialFile,
147
- roles: [],
148
- });
149
- }
150
- catch {
151
- return unboundBinding(false);
152
- }
153
- const host = createPlatformHost({ config: hostConfig });
154
- const service = {
155
- start: () => host.start(),
156
- stop: () => host.stop(),
157
- restart: () => host.restart(),
158
- status: async () => ({ readiness: (await host.status()).readiness }),
159
- };
160
- return { behaviorAdapter: createBehaviorAdapter(service, input.config) };
161
- }
171
+ }
172
+ return {
173
+ result: (await running(context))
174
+ ? failed("STOP_FAILED", "platform-host is running without an owned lifecycle handle")
175
+ : base,
176
+ observedEffects: [],
177
+ };
178
+ },
179
+ };
@@ -3,7 +3,7 @@ export declare const descriptor: {
3
3
  readonly contractVersion: "1.0.0";
4
4
  readonly moduleRef: "platform-host";
5
5
  readonly packageName: "@tomflow/proflow-platform-host";
6
- readonly moduleVersion: "0.1.5";
6
+ readonly moduleVersion: "0.1.7";
7
7
  readonly kind: "service";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -33,67 +33,14 @@ export declare const descriptor: {
33
33
  readonly runtime: "node";
34
34
  readonly versionRange: ">=24.19.0";
35
35
  }];
36
- readonly configSlots: readonly [{
37
- readonly key: "stateRoot";
38
- readonly type: "path";
39
- readonly required: true;
40
- readonly description: "Absolute .proflow owner state root";
41
- }, {
42
- readonly key: "workspaceRoot";
43
- readonly type: "path";
44
- readonly required: true;
45
- readonly description: "Absolute Task document workspace root";
46
- }, {
47
- readonly key: "gatewayTransportCredentialFile";
48
- readonly type: "path";
49
- readonly required: true;
50
- readonly sensitive: true;
51
- readonly description: "File containing the dedicated credential accepted from agent-gateway";
52
- }, {
53
- readonly key: "executionBaseUrl";
54
- readonly type: "url";
55
- readonly required: true;
56
- readonly description: "Loopback Execution Runtime public transport";
57
- }, {
58
- readonly key: "executionTransportCredentialFile";
59
- readonly type: "path";
60
- readonly required: true;
61
- readonly sensitive: true;
62
- readonly description: "File containing the credential used for Platform Host calls to Execution Runtime";
63
- }, {
64
- readonly key: "modelTransportCredentialFile";
65
- readonly type: "path";
66
- readonly required: true;
67
- readonly sensitive: true;
68
- readonly description: "File containing the credential used for Platform Host calls to Model Runtime";
69
- }, {
70
- readonly key: "modelBaseUrl";
71
- readonly type: "url";
72
- readonly required: true;
73
- readonly description: "Loopback Model Runtime public transport";
74
- }];
75
- readonly lifecycle: {
76
- readonly supported: readonly ["describe", "preflight", "status", "verify", "doctor", "start", "stop", "restart", "uninstall"];
77
- };
78
- readonly verification: {
79
- readonly checks: readonly [{
80
- readonly id: "platform-host-readiness";
81
- readonly description: "Host transport and current owner dependencies are ready";
82
- readonly lifecycle: "verify";
83
- }];
84
- };
36
+ readonly configSlots: readonly [];
85
37
  readonly effects: readonly [{
86
38
  readonly kind: "process";
87
39
  readonly description: "Manage the platform-host process";
88
40
  readonly retention: "remove";
89
41
  }];
90
- readonly documentation: readonly [{
91
- readonly id: "overview";
92
- readonly path: "./README.md";
93
- readonly description: "Platform Host package overview";
94
- }, {
95
- readonly id: "configuration";
96
- readonly path: "./CONFIGURATION.md";
97
- readonly description: "Module configuration fields, sources and materialization instructions";
98
- }];
42
+ readonly documentation: {
43
+ readonly docs: "DOCS.md";
44
+ readonly setup: "SETUP.md";
45
+ };
99
46
  };
@@ -3,7 +3,7 @@ export const descriptor = {
3
3
  contractVersion: "1.0.0",
4
4
  moduleRef: "platform-host",
5
5
  packageName: "@tomflow/proflow-platform-host",
6
- moduleVersion: "0.1.5",
6
+ moduleVersion: "0.1.7",
7
7
  kind: "service",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -42,75 +42,7 @@ export const descriptor = {
42
42
  versionRange: ">=24.19.0",
43
43
  },
44
44
  ],
45
- configSlots: [
46
- {
47
- key: "stateRoot",
48
- type: "path",
49
- required: true,
50
- description: "Absolute .proflow owner state root",
51
- },
52
- {
53
- key: "workspaceRoot",
54
- type: "path",
55
- required: true,
56
- description: "Absolute Task document workspace root",
57
- },
58
- {
59
- key: "gatewayTransportCredentialFile",
60
- type: "path",
61
- required: true,
62
- sensitive: true,
63
- description: "File containing the dedicated credential accepted from agent-gateway",
64
- },
65
- {
66
- key: "executionBaseUrl",
67
- type: "url",
68
- required: true,
69
- description: "Loopback Execution Runtime public transport",
70
- },
71
- {
72
- key: "executionTransportCredentialFile",
73
- type: "path",
74
- required: true,
75
- sensitive: true,
76
- description: "File containing the credential used for Platform Host calls to Execution Runtime",
77
- },
78
- {
79
- key: "modelTransportCredentialFile",
80
- type: "path",
81
- required: true,
82
- sensitive: true,
83
- description: "File containing the credential used for Platform Host calls to Model Runtime",
84
- },
85
- {
86
- key: "modelBaseUrl",
87
- type: "url",
88
- required: true,
89
- description: "Loopback Model Runtime public transport",
90
- },
91
- ],
92
- lifecycle: {
93
- supported: [
94
- "describe",
95
- "preflight",
96
- "status",
97
- "verify",
98
- "doctor",
99
- "start",
100
- "stop",
101
- "restart",
102
- "uninstall",
103
- ],
104
- },
105
- verification: {
106
- checks: [
107
- {
108
- id: "platform-host-readiness",
109
- description: "Host transport and current owner dependencies are ready",
110
- lifecycle: "verify",
111
- },
112
- ],
113
- },
45
+ configSlots: [],
114
46
  effects: [
115
47
  {
116
48
  kind: "process",
@@ -118,16 +50,8 @@ export const descriptor = {
118
50
  retention: "remove",
119
51
  },
120
52
  ],
121
- documentation: [
122
- {
123
- id: "overview",
124
- path: "./README.md",
125
- description: "Platform Host package overview",
126
- },
127
- {
128
- id: "configuration",
129
- path: "./CONFIGURATION.md",
130
- description: "Module configuration fields, sources and materialization instructions",
131
- },
132
- ],
53
+ documentation: {
54
+ docs: "DOCS.md",
55
+ setup: "SETUP.md",
56
+ },
133
57
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-platform-host",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -19,23 +19,24 @@
19
19
  "proflow.module.json",
20
20
  "conformance.json",
21
21
  "README.md",
22
- "CONFIGURATION.md"
22
+ "DOCS.md",
23
+ "SETUP.md"
23
24
  ],
24
25
  "dependencies": {
25
26
  "zod": "4.1.12",
26
- "@tomflow/proflow-agent-runtime": "^0.1.3",
27
- "@tomflow/proflow-execution-browser-extension": "^0.1.4",
28
- "@tomflow/proflow-execution-contracts": "^0.1.3",
29
- "@tomflow/proflow-task-store-sqlite": "^0.1.3",
30
- "@tomflow/proflow-module-contract": "^0.1.3",
31
- "@tomflow/proflow-task-orchestration": "^0.1.2",
32
- "@tomflow/proflow-task-migration-runner": "^0.1.3"
27
+ "@tomflow/proflow-agent-runtime": "^0.1.5",
28
+ "@tomflow/proflow-module-contract": "^0.1.5",
29
+ "@tomflow/proflow-execution-browser-extension": "^0.1.6",
30
+ "@tomflow/proflow-task-migration-runner": "^0.1.5",
31
+ "@tomflow/proflow-task-store-sqlite": "^0.1.5",
32
+ "@tomflow/proflow-task-orchestration": "^0.1.4",
33
+ "@tomflow/proflow-execution-contracts": "^0.1.5"
33
34
  },
34
35
  "devDependencies": {
35
- "@tomflow/proflow-deployment-conformance": "^0.1.3",
36
- "@tomflow/proflow-model-runtime": "^0.1.6",
37
- "@tomflow/proflow-agent-gateway": "^0.1.5",
38
- "@tomflow/proflow-execution-runtime": "^0.1.6"
36
+ "@tomflow/proflow-execution-runtime": "^0.1.8",
37
+ "@tomflow/proflow-deployment-conformance": "^0.1.5",
38
+ "@tomflow/proflow-agent-gateway": "^0.1.7",
39
+ "@tomflow/proflow-model-runtime": "^0.1.8"
39
40
  },
40
41
  "description": "Provides the ProFlow local application composition root that binds Task, Agent, Execution and Model owner transports.",
41
42
  "keywords": [
@@ -3,7 +3,7 @@
3
3
  "contractVersion": "1.0.0",
4
4
  "moduleRef": "platform-host",
5
5
  "packageName": "@tomflow/proflow-platform-host",
6
- "moduleVersion": "0.1.5",
6
+ "moduleVersion": "0.1.7",
7
7
  "kind": "service",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",
@@ -42,75 +42,7 @@
42
42
  "versionRange": ">=24.19.0"
43
43
  }
44
44
  ],
45
- "configSlots": [
46
- {
47
- "key": "stateRoot",
48
- "type": "path",
49
- "required": true,
50
- "description": "Absolute .proflow owner state root"
51
- },
52
- {
53
- "key": "workspaceRoot",
54
- "type": "path",
55
- "required": true,
56
- "description": "Absolute Task document workspace root"
57
- },
58
- {
59
- "key": "gatewayTransportCredentialFile",
60
- "type": "path",
61
- "required": true,
62
- "sensitive": true,
63
- "description": "File containing the dedicated credential accepted from agent-gateway"
64
- },
65
- {
66
- "key": "executionBaseUrl",
67
- "type": "url",
68
- "required": true,
69
- "description": "Loopback Execution Runtime public transport"
70
- },
71
- {
72
- "key": "executionTransportCredentialFile",
73
- "type": "path",
74
- "required": true,
75
- "sensitive": true,
76
- "description": "File containing the credential used for Platform Host calls to Execution Runtime"
77
- },
78
- {
79
- "key": "modelTransportCredentialFile",
80
- "type": "path",
81
- "required": true,
82
- "sensitive": true,
83
- "description": "File containing the credential used for Platform Host calls to Model Runtime"
84
- },
85
- {
86
- "key": "modelBaseUrl",
87
- "type": "url",
88
- "required": true,
89
- "description": "Loopback Model Runtime public transport"
90
- }
91
- ],
92
- "lifecycle": {
93
- "supported": [
94
- "describe",
95
- "preflight",
96
- "status",
97
- "verify",
98
- "doctor",
99
- "start",
100
- "stop",
101
- "restart",
102
- "uninstall"
103
- ]
104
- },
105
- "verification": {
106
- "checks": [
107
- {
108
- "id": "platform-host-readiness",
109
- "description": "Host transport and current owner dependencies are ready",
110
- "lifecycle": "verify"
111
- }
112
- ]
113
- },
45
+ "configSlots": [],
114
46
  "effects": [
115
47
  {
116
48
  "kind": "process",
@@ -118,16 +50,8 @@
118
50
  "retention": "remove"
119
51
  }
120
52
  ],
121
- "documentation": [
122
- {
123
- "id": "overview",
124
- "path": "./README.md",
125
- "description": "Platform Host package overview"
126
- },
127
- {
128
- "id": "configuration",
129
- "path": "./CONFIGURATION.md",
130
- "description": "Module configuration fields, sources and materialization instructions"
131
- }
132
- ]
53
+ "documentation": {
54
+ "docs": "DOCS.md",
55
+ "setup": "SETUP.md"
56
+ }
133
57
  }
package/CONFIGURATION.md DELETED
@@ -1,29 +0,0 @@
1
- # platform-host configuration
2
-
3
- Canonical public config: `.proflow/config/platform-host.json`
4
-
5
- This file is Workspace-owned data. `platform uninstall` does not delete it. Values are JSON strings. Raw secrets must not be stored here; `secretRef` fields contain opaque references only.
6
-
7
- ## Fields
8
-
9
- | Key | Type | Required | Sensitive | Source | Meaning |
10
- |---|---|---:|---:|---|---|
11
- | `stateRoot` | `path` | yes | no | User or owning Module supplies an absolute/local path that exists on this Workspace. | Absolute .proflow owner state root |
12
- | `workspaceRoot` | `path` | yes | no | User or owning Module supplies an absolute/local path that exists on this Workspace. | Absolute Task document workspace root |
13
- | `gatewayTransportCredentialFile` | `path` | yes | yes | User or owning Module supplies an absolute/local path that exists on this Workspace. | File containing the dedicated credential accepted from agent-gateway |
14
- | `executionBaseUrl` | `url` | yes | no | User or owning external/runtime Module supplies the reachable endpoint URL. | Loopback Execution Runtime public transport |
15
- | `executionTransportCredentialFile` | `path` | yes | yes | User or owning Module supplies an absolute/local path that exists on this Workspace. | File containing the credential used for Platform Host calls to Execution Runtime |
16
- | `modelTransportCredentialFile` | `path` | yes | yes | User or owning Module supplies an absolute/local path that exists on this Workspace. | File containing the credential used for Platform Host calls to Model Runtime |
17
- | `modelBaseUrl` | `url` | yes | no | User or owning external/runtime Module supplies the reachable endpoint URL. | Loopback Model Runtime public transport |
18
-
19
- ## Materialize
20
-
21
- Create or update the canonical JSON object at:
22
-
23
- `.proflow/config/platform-host.json`
24
-
25
- Use only declared keys and string values. Do not create a second Platform configuration database.
26
-
27
- ## Base completion check
28
-
29
- Run `platform modules`. This Module should no longer report required keys in `missingConfig`. `platform start` performs the authoritative Module-owned validation before starting anything.