@tomflow/proflow-platform-host 0.1.18 → 0.1.20

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.
@@ -6,7 +6,7 @@ export declare const behaviorAdapter: {
6
6
  ok: true;
7
7
  status: "SUCCEEDED";
8
8
  moduleRef: "platform-host";
9
- moduleVersion: "0.1.18";
9
+ moduleVersion: "0.1.20";
10
10
  data: {
11
11
  endpoint: string;
12
12
  stateRoot: string;
@@ -24,7 +24,7 @@ export declare const behaviorAdapter: {
24
24
  readonly ok: true;
25
25
  readonly status: "SUCCEEDED";
26
26
  readonly moduleRef: "platform-host";
27
- readonly moduleVersion: "0.1.18";
27
+ readonly moduleVersion: "0.1.20";
28
28
  };
29
29
  observedEffects: string[];
30
30
  }>;
@@ -34,7 +34,7 @@ export declare const behaviorAdapter: {
34
34
  ok: true;
35
35
  status: "SUCCEEDED";
36
36
  moduleRef: "platform-host";
37
- moduleVersion: "0.1.18";
37
+ moduleVersion: "0.1.20";
38
38
  data: {
39
39
  setupStatus: "READY";
40
40
  runtimeStatus: "RUNNING" | "STOPPED";
@@ -55,7 +55,7 @@ export declare const behaviorAdapter: {
55
55
  ok: true;
56
56
  status: "SUCCEEDED";
57
57
  moduleRef: "platform-host";
58
- moduleVersion: "0.1.18";
58
+ moduleVersion: "0.1.20";
59
59
  data: {
60
60
  endpoint: string;
61
61
  stateRoot: string;
@@ -73,7 +73,7 @@ export declare const behaviorAdapter: {
73
73
  ok: true;
74
74
  status: "SUCCEEDED";
75
75
  moduleRef: "platform-host";
76
- moduleVersion: "0.1.18";
76
+ moduleVersion: "0.1.20";
77
77
  data: {
78
78
  docs: string;
79
79
  };
@@ -86,7 +86,7 @@ export declare const behaviorAdapter: {
86
86
  ok: true;
87
87
  status: "SUCCEEDED";
88
88
  moduleRef: "platform-host";
89
- moduleVersion: "0.1.18";
89
+ moduleVersion: "0.1.20";
90
90
  data: {
91
91
  host: string;
92
92
  port: number;
@@ -97,7 +97,7 @@ export declare const behaviorAdapter: {
97
97
  result: {
98
98
  contract: "deployment.result.v1";
99
99
  moduleRef: "platform-host";
100
- moduleVersion: "0.1.18";
100
+ moduleVersion: "0.1.20";
101
101
  ok: false;
102
102
  status: "FAILED";
103
103
  error: {
@@ -114,7 +114,7 @@ export declare const behaviorAdapter: {
114
114
  readonly ok: true;
115
115
  readonly status: "SUCCEEDED";
116
116
  readonly moduleRef: "platform-host";
117
- readonly moduleVersion: "0.1.18";
117
+ readonly moduleVersion: "0.1.20";
118
118
  };
119
119
  observedEffects: string[];
120
120
  } | {
@@ -123,11 +123,11 @@ export declare const behaviorAdapter: {
123
123
  readonly ok: true;
124
124
  readonly status: "SUCCEEDED";
125
125
  readonly moduleRef: "platform-host";
126
- readonly moduleVersion: "0.1.18";
126
+ readonly moduleVersion: "0.1.20";
127
127
  } | {
128
128
  contract: "deployment.result.v1";
129
129
  moduleRef: "platform-host";
130
- moduleVersion: "0.1.18";
130
+ moduleVersion: "0.1.20";
131
131
  ok: false;
132
132
  status: "FAILED";
133
133
  error: {
@@ -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.18";
6
+ readonly moduleVersion: "0.1.20";
7
7
  readonly kind: "service";
8
8
  readonly templateVersion: "1.0.0";
9
9
  readonly platformCompatibility: ">=1.0.0 <2.0.0";
@@ -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.18",
6
+ moduleVersion: "0.1.20",
7
7
  kind: "service",
8
8
  templateVersion: "1.0.0",
9
9
  platformCompatibility: ">=1.0.0 <2.0.0",
@@ -192,6 +192,7 @@ export type PlatformHostTaskDriverPorts = {
192
192
  } | null;
193
193
  canDrive: boolean;
194
194
  blockedReason: string | null;
195
+ resumeSignalRef: string | null;
195
196
  }>;
196
197
  getNodeContext(taskId: string, nodeId: string): Promise<{
197
198
  task: {
package/dist/src/index.js CHANGED
@@ -4,6 +4,7 @@ import { appendFile, chmod, mkdir, readFile, stat, writeFile, } from "node:fs/pr
4
4
  import { createServer } from "node:http";
5
5
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
6
6
  import { createAgentRuntime } from "@tomflow/proflow-agent-runtime";
7
+ import { executionCapabilityIds, } from "@tomflow/proflow-execution-contracts";
7
8
  import { applyMigrations } from "@tomflow/proflow-task-migration-runner";
8
9
  import { createTaskServices, publicOperationNames, } from "@tomflow/proflow-task-orchestration";
9
10
  import { SqliteTaskStore } from "@tomflow/proflow-task-store-sqlite";
@@ -324,6 +325,11 @@ function string(value, name) {
324
325
  throw new TypeError(`${name} must be a non-empty string`);
325
326
  return value;
326
327
  }
328
+ function positiveInteger(value, name) {
329
+ if (!Number.isInteger(value) || Number(value) <= 0)
330
+ throw new TypeError(`${name} must be a positive integer`);
331
+ return Number(value);
332
+ }
327
333
  function unwrap(result) {
328
334
  if (!result.ok || result.data === undefined)
329
335
  throw new Error(`OWNER_CONTRACT_FAILED:${JSON.stringify(result.error)}`);
@@ -628,6 +634,37 @@ async function constructGraph(config, executionCredential, modelCredential) {
628
634
  }
629
635
  return rawRecord;
630
636
  };
637
+ const admissionError = (code, httpStatus = 403) => {
638
+ throw Object.assign(new Error(code), { httpStatus });
639
+ };
640
+ const admitExactNodeExecution = async (input, authenticatedRoleRef) => {
641
+ const taskId = string(input.taskId, "taskId");
642
+ const nodeId = string(input.nodeId, "nodeId");
643
+ const runNo = positiveInteger(input.runNo, "runNo");
644
+ const workerRef = await admitTaskParticipant(taskId, authenticatedRoleRef);
645
+ await agent.validateWorker({ authenticatedRoleRef, taskId, workerRef });
646
+ const taskFact = taskFacts(taskId);
647
+ const nodeContext = unwrap(task.queries.getNodeContext({ taskId, nodeId }));
648
+ if (taskFact.status !== "ACTIVE")
649
+ admissionError("EXECUTION_TASK_NOT_ACTIVE");
650
+ if (taskFact.currentNodeId !== nodeId)
651
+ admissionError("EXECUTION_NODE_NOT_CURRENT");
652
+ if (nodeContext.node.status !== "IN_PROGRESS")
653
+ admissionError("EXECUTION_NODE_NOT_RUNNING");
654
+ if (nodeContext.node.runNo !== runNo)
655
+ admissionError("EXECUTION_GENERATION_MISMATCH");
656
+ const nodeBinding = taskFact.roleBindings.find((binding) => binding.agentPackageRef === nodeContext.node.requiredAgentPackageRef);
657
+ if (!nodeBinding)
658
+ throw Object.assign(new Error("TASK_ROLE_BINDING_REQUIRED"), {
659
+ httpStatus: 403,
660
+ });
661
+ if (nodeBinding.roleRef !== authenticatedRoleRef)
662
+ admissionError("EXECUTION_ROLE_SCOPE_MISMATCH");
663
+ if (nodeBinding.workerRef !== workerRef ||
664
+ nodeContext.node.workerRef !== workerRef)
665
+ admissionError("EXECUTION_WORKER_SCOPE_MISMATCH");
666
+ return { taskId, nodeId, runNo, workerRef };
667
+ };
631
668
  const route = async (operationId, authenticatedRoleRef, rawInput, context) => {
632
669
  const role = agent.getRegisteredRole(authenticatedRoleRef);
633
670
  if (!roleOperations[role.agentPackageRef]?.has(operationId))
@@ -687,26 +724,26 @@ async function constructGraph(config, executionCredential, modelCredential) {
687
724
  : { ...canonicalTaskInput, actorRef });
688
725
  if (operationId === "getTaskDocument")
689
726
  return fileBridgeOutputForTaskResult(taskResult);
727
+ if (operationId === "getNodeContext" &&
728
+ roleOperations[role.agentPackageRef]?.has("executeCapability")) {
729
+ return {
730
+ ...object(taskResult, "node context"),
731
+ executionCapabilityIds: [...executionCapabilityIds],
732
+ };
733
+ }
690
734
  return taskResult;
691
735
  }
692
736
  if (operationId === "executeCapability") {
693
- const taskId = typeof input.taskId === "string" ? input.taskId : undefined;
694
- let canonicalWorkerRef;
695
- if (taskId) {
696
- canonicalWorkerRef = await admitTaskParticipant(taskId, authenticatedRoleRef, typeof input.workerRef === "string" ? input.workerRef : undefined);
697
- await agent.validateWorker({
698
- authenticatedRoleRef,
699
- taskId,
700
- workerRef: canonicalWorkerRef,
701
- });
702
- }
737
+ const scope = await admitExactNodeExecution(input, authenticatedRoleRef);
738
+ const { workerRef: _suppliedWorkerRef, projectRoot: _suppliedProjectRoot, roleRef: _suppliedRoleRef, callerRef: _suppliedCallerRef, ...ownerInput } = input;
703
739
  const result = await execution.invoke(operationId, {
704
- ...input,
740
+ ...ownerInput,
705
741
  callerRef: authenticatedRoleRef,
706
742
  roleRef: authenticatedRoleRef,
707
- ...(canonicalWorkerRef !== undefined
708
- ? { workerRef: canonicalWorkerRef }
709
- : {}),
743
+ taskId: scope.taskId,
744
+ nodeId: scope.nodeId,
745
+ runNo: scope.runNo,
746
+ workerRef: scope.workerRef,
710
747
  });
711
748
  // A normal Action may complete synchronously inside the current Worker Turn.
712
749
  // Do not manufacture a Browser RESUME for every terminal Execution record.
@@ -858,14 +895,14 @@ async function constructGraph(config, executionCredential, modelCredential) {
858
895
  return false;
859
896
  if (request.runNo !== nodeContext.node.runNo)
860
897
  return false;
861
- if (!browserCapability &&
862
- nodeContext.node.status !== "IN_PROGRESS")
898
+ if (!browserCapability && nodeContext.node.status !== "IN_PROGRESS")
863
899
  return false;
864
900
  const nodeBinding = taskFact.roleBindings.find((candidate) => candidate.agentPackageRef ===
865
901
  nodeContext.node.requiredAgentPackageRef);
866
902
  if (!nodeBinding?.workerRef)
867
903
  return false;
868
- const scopedRoleRef = request.roleRef ?? (internalBrowserCaller ? undefined : request.callerRef);
904
+ const scopedRoleRef = request.roleRef ??
905
+ (internalBrowserCaller ? undefined : request.callerRef);
869
906
  if (scopedRoleRef !== nodeBinding.roleRef)
870
907
  return false;
871
908
  if (request.workerRef !== nodeBinding.workerRef)
@@ -903,6 +940,7 @@ async function constructGraph(config, executionCredential, modelCredential) {
903
940
  const resumeWake = nodeContext.node.status === "IN_PROGRESS" &&
904
941
  (trigger === "RECOVERY_RESUME" ||
905
942
  trigger === "EXECUTION_RESULT_READY" ||
943
+ trigger === "TASK_RESUMED" ||
906
944
  trigger === "PEER_REPLY_READY");
907
945
  if (!readyWake && !resumeWake)
908
946
  return false;
@@ -1157,6 +1195,22 @@ async function constructGraph(config, executionCredential, modelCredential) {
1157
1195
  actorRef: "extension:human",
1158
1196
  idempotencyKey: string(value.idempotencyKey, "idempotencyKey"),
1159
1197
  }));
1198
+ if (operation === "message.acknowledge")
1199
+ return unwrap(task.commands.acknowledgeMessage({
1200
+ messageId: string(value.messageId, "messageId"),
1201
+ ...(typeof value.resolution === "string"
1202
+ ? { resolution: value.resolution }
1203
+ : {}),
1204
+ actorRef: "extension:human",
1205
+ idempotencyKey: string(value.idempotencyKey, "idempotencyKey"),
1206
+ }));
1207
+ if (operation === "task.resume")
1208
+ return unwrap(task.commands.resumeTask({
1209
+ taskId: string(value.taskId, "taskId"),
1210
+ expectedTaskVersion: positiveInteger(value.expectedTaskVersion, "expectedTaskVersion"),
1211
+ actorRef: "extension:human",
1212
+ idempotencyKey: string(value.idempotencyKey, "idempotencyKey"),
1213
+ }));
1160
1214
  if (operation === "node.reopen")
1161
1215
  return unwrap(task.commands.reopenNode({
1162
1216
  taskId: string(value.taskId, "taskId"),
@@ -1458,15 +1512,16 @@ async function constructGraph(config, executionCredential, modelCredential) {
1458
1512
  });
1459
1513
  return admitExecutionRead(authenticatedRoleRef, record);
1460
1514
  }
1461
- const taskId = typeof value.taskId === "string" ? value.taskId : undefined;
1462
- let canonicalWorkerRef;
1463
- if (taskId)
1464
- canonicalWorkerRef = await admitTaskParticipant(taskId, authenticatedRoleRef, typeof value.workerRef === "string" ? value.workerRef : undefined);
1515
+ const scope = await admitExactNodeExecution(value, authenticatedRoleRef);
1516
+ const { workerRef: _suppliedWorkerRef, projectRoot: _suppliedProjectRoot, roleRef: _suppliedRoleRef, callerRef: _suppliedCallerRef, ...ownerInput } = value;
1465
1517
  const record = await execution.invoke("lookupExecutionIntent", {
1466
- ...value,
1518
+ ...ownerInput,
1467
1519
  callerRef: authenticatedRoleRef,
1468
1520
  roleRef: authenticatedRoleRef,
1469
- ...(canonicalWorkerRef ? { workerRef: canonicalWorkerRef } : {}),
1521
+ taskId: scope.taskId,
1522
+ nodeId: scope.nodeId,
1523
+ runNo: scope.runNo,
1524
+ workerRef: scope.workerRef,
1470
1525
  });
1471
1526
  return admitExecutionRead(authenticatedRoleRef, record);
1472
1527
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-platform-host",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -24,19 +24,19 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "zod": "4.1.12",
27
- "@tomflow/proflow-agent-runtime": "^0.1.13",
28
- "@tomflow/proflow-execution-browser-extension": "^0.1.42",
29
27
  "@tomflow/proflow-execution-contracts": "^0.1.10",
28
+ "@tomflow/proflow-task-store-sqlite": "^0.1.11",
29
+ "@tomflow/proflow-execution-browser-extension": "^0.1.50",
30
+ "@tomflow/proflow-task-orchestration": "^0.1.11",
30
31
  "@tomflow/proflow-module-contract": "^0.1.13",
31
32
  "@tomflow/proflow-task-migration-runner": "^0.1.11",
32
- "@tomflow/proflow-task-store-sqlite": "^0.1.11",
33
- "@tomflow/proflow-task-orchestration": "^0.1.10"
33
+ "@tomflow/proflow-agent-runtime": "^0.1.14"
34
34
  },
35
35
  "devDependencies": {
36
- "@tomflow/proflow-agent-gateway": "^0.1.15",
37
- "@tomflow/proflow-deployment-conformance": "^0.1.13",
36
+ "@tomflow/proflow-agent-gateway": "^0.1.16",
37
+ "@tomflow/proflow-model-runtime": "^0.1.24",
38
38
  "@tomflow/proflow-execution-runtime": "^0.1.18",
39
- "@tomflow/proflow-model-runtime": "^0.1.24"
39
+ "@tomflow/proflow-deployment-conformance": "^0.1.13"
40
40
  },
41
41
  "description": "Provides the ProFlow local application composition root that binds Task, Agent, Execution and Model owner transports.",
42
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.18",
6
+ "moduleVersion": "0.1.20",
7
7
  "kind": "service",
8
8
  "templateVersion": "1.0.0",
9
9
  "platformCompatibility": ">=1.0.0 <2.0.0",
package/CHANGELOG.md DELETED
@@ -1,13 +0,0 @@
1
- # @tomflow/proflow-platform-host
2
-
3
- ## 0.1.18
4
-
5
- ### Patch Changes
6
-
7
- - Close Real-3 node generation identity fencing across Platform Host admission, durable Execution idempotency, and Observer/Approval resume provenance.
8
-
9
- ## 0.1.17
10
-
11
- ### Patch Changes
12
-
13
- - Harden Real-3 Browser Carrier reality: controlled ChatGPT composer submission, authoritative action-permission classification, bounded binding-race deferral, Carrier Attention web relay and restart recovery, and human-deny precedence across automatic recovery.