@stigmer/runner 3.29.0 → 3.31.0

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.
Files changed (91) hide show
  1. package/README.md +5 -0
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/activities/call-eval.d.ts +16 -0
  4. package/dist/activities/call-eval.js +54 -1
  5. package/dist/activities/call-eval.js.map +1 -1
  6. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +1 -0
  7. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  8. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +1 -0
  9. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  10. package/dist/activities/hydrate-workflow-execution.d.ts +1 -1
  11. package/dist/activities/workflow-event-activities.d.ts +2 -2
  12. package/dist/activities/workflow-event-activities.js +2 -2
  13. package/dist/config.d.ts +8 -0
  14. package/dist/config.js +2 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/harness/transcript/builder.d.ts +3 -2
  17. package/dist/harness/transcript/builder.js +28 -8
  18. package/dist/harness/transcript/builder.js.map +1 -1
  19. package/dist/runner-manager.d.ts +9 -0
  20. package/dist/runner-manager.js +3 -0
  21. package/dist/runner-manager.js.map +1 -1
  22. package/dist/runner.d.ts +9 -0
  23. package/dist/runner.js +3 -1
  24. package/dist/runner.js.map +1 -1
  25. package/dist/shared/approval-policy.d.ts +5 -0
  26. package/dist/shared/approval-policy.js +8 -0
  27. package/dist/shared/approval-policy.js.map +1 -1
  28. package/dist/shared/args-preview.d.ts +12 -5
  29. package/dist/shared/args-preview.js +12 -5
  30. package/dist/shared/args-preview.js.map +1 -1
  31. package/dist/shared/runner-credential-keys.d.ts +0 -29
  32. package/dist/shared/runner-credential-keys.js +8 -0
  33. package/dist/shared/runner-credential-keys.js.map +1 -1
  34. package/dist/worker.d.ts +2 -4
  35. package/dist/worker.js +3 -4
  36. package/dist/worker.js.map +1 -1
  37. package/dist/workflow-engine/tasks/run.d.ts +15 -1
  38. package/dist/workflow-engine/tasks/run.js +18 -1
  39. package/dist/workflow-engine/tasks/run.js.map +1 -1
  40. package/dist/workflows/call-agent-orchestrator.d.ts +1 -1
  41. package/dist/workflows/call-agent-orchestrator.js +1 -1
  42. package/dist/workflows/engine-core.d.ts +28 -8
  43. package/dist/workflows/engine-core.js +9 -7
  44. package/dist/workflows/engine-core.js.map +1 -1
  45. package/dist/workflows/index.d.ts +22 -7
  46. package/dist/workflows/index.js +22 -7
  47. package/dist/workflows/index.js.map +1 -1
  48. package/dist/workflows/workflow-signals.d.ts +3 -3
  49. package/dist/workflows/workflow-signals.js +3 -3
  50. package/package.json +5 -5
  51. package/src/__test-utils__/config-fixture.ts +1 -0
  52. package/src/__test-utils__/workflows/index.ts +15 -0
  53. package/src/__test-utils__/workflows/inline-model.ts +34 -0
  54. package/src/__tests__/dispatch-surface-e2e.test.ts +212 -0
  55. package/src/__tests__/golden-e2e.test.ts +4 -3
  56. package/src/__tests__/history-encryption-e2e.test.ts +1 -1
  57. package/src/__tests__/runner.test.ts +20 -0
  58. package/src/activities/__tests__/call-eval.test.ts +115 -0
  59. package/src/activities/__tests__/classify-tool-approvals.test.ts +1 -0
  60. package/src/activities/__tests__/discover-mcp-server.test.ts +1 -0
  61. package/src/activities/call-eval.ts +59 -1
  62. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +1 -0
  63. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +1 -0
  64. package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +1 -0
  65. package/src/activities/hydrate-workflow-execution.ts +1 -1
  66. package/src/activities/workflow-event-activities.ts +2 -2
  67. package/src/config.ts +10 -0
  68. package/src/harness/transcript/__tests__/builder.test.ts +56 -1
  69. package/src/harness/transcript/builder.ts +29 -8
  70. package/src/runner-manager.ts +14 -0
  71. package/src/runner.ts +14 -0
  72. package/src/shared/__tests__/approval-policy.test.ts +10 -0
  73. package/src/shared/__tests__/args-preview.test.ts +50 -1
  74. package/src/shared/__tests__/artifact-storage.test.ts +1 -0
  75. package/src/shared/__tests__/runner-credential-store.test.ts +20 -0
  76. package/src/shared/approval-policy.ts +7 -0
  77. package/src/shared/args-preview.ts +12 -5
  78. package/src/shared/runner-credential-keys.ts +12 -0
  79. package/src/worker.ts +3 -4
  80. package/src/workflow-engine/__tests__/tasks/run.test.ts +25 -0
  81. package/src/workflow-engine/tasks/run.ts +21 -1
  82. package/src/workflows/__tests__/barrel.test.ts +52 -0
  83. package/src/workflows/__tests__/{execute-serverless-workflow.test.ts → engine-inline-model.test.ts} +16 -4
  84. package/src/workflows/call-agent-orchestrator.ts +1 -1
  85. package/src/workflows/engine-core.ts +34 -9
  86. package/src/workflows/index.ts +22 -10
  87. package/src/workflows/workflow-signals.ts +3 -3
  88. package/dist/workflows/execute-serverless-workflow.d.ts +0 -32
  89. package/dist/workflows/execute-serverless-workflow.js +0 -36
  90. package/dist/workflows/execute-serverless-workflow.js.map +0 -1
  91. package/src/workflows/execute-serverless-workflow.ts +0 -60
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { loadTemporalConnectionConfig } from "@stigmer/temporal-codecs";
2
3
  import {
3
4
  captureRunnerSecrets,
4
5
  getRunnerSecret,
@@ -87,6 +88,25 @@ describe("captureRunnerSecrets", () => {
87
88
  expect(RUNNER_SECRET_ENV_KEYS, `'${key}' must be in the scrub list`).toContain(key);
88
89
  }
89
90
  });
91
+
92
+ it("takes the Temporal API key and client key into custody, and the connection settings still read them", () => {
93
+ // Pinned by name, like the encryption keys: a runner that left either
94
+ // in process.env would hand every agent shell a credential to Temporal.
95
+ // Temporal's own TEMPORAL_API_KEY is the user's and stays untouched.
96
+ for (const key of ["STIGMER_TEMPORAL_API_KEY", "STIGMER_TEMPORAL_TLS_CLIENT_KEY_DATA"]) {
97
+ expect(RUNNER_CREDENTIAL_ENV_KEYS, `'${key}' must be a captured credential`).toContain(key);
98
+ }
99
+ expect(RUNNER_SECRET_ENV_KEYS).not.toContain("TEMPORAL_API_KEY");
100
+
101
+ process.env.STIGMER_TEMPORAL_API_KEY = "temporal-key";
102
+ captureRunnerSecrets();
103
+
104
+ expect(process.env.STIGMER_TEMPORAL_API_KEY).toBeUndefined();
105
+ expect(loadTemporalConnectionConfig(getRunnerSecret)).toEqual({
106
+ tls: {},
107
+ apiKey: "temporal-key",
108
+ });
109
+ });
90
110
  });
91
111
 
92
112
  describe("getRunnerSecret", () => {
@@ -18,6 +18,7 @@
18
18
  import type { ToolApprovalPolicy } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/spec_pb";
19
19
  import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
20
20
  import { ApprovalAction, ApprovalMode, ApprovalPolicySource } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
21
+ import { SENSITIVE_ARG_KEYS } from "./args-preview.js";
21
22
  import { toolApprovalCategory, type ToolApprovalCategory } from "./tool-kind.js";
22
23
  import type { ResolvedMcpServer } from "./mcp-resolver.js";
23
24
 
@@ -451,6 +452,11 @@ export function lookupMcpToolPolicy(
451
452
  * - {{args.field_name}} — replaced with the argument value
452
453
  * - {{tool_name}} — replaced with the tool name
453
454
  * - Missing fields are replaced with "<unknown>"
455
+ * - A secret-keyed field ({@link SENSITIVE_ARG_KEYS}) is replaced with
456
+ * "[REDACTED]" (stigmer#1119): the message is stored on the row and shown on
457
+ * the approval card, which must carry no more than the redacted preview.
458
+ * Every approval message in the runner, native and Cursor alike, resolves
459
+ * here, so this is the one place the rule applies to it.
454
460
  */
455
461
  export function resolveApprovalMessage(
456
462
  template: string,
@@ -460,6 +466,7 @@ export function resolveApprovalMessage(
460
466
  return template
461
467
  .replace(/\{\{tool_name\}\}/g, toolName)
462
468
  .replace(/\{\{args\.(\w+)\}\}/g, (_match, field: string) => {
469
+ if (SENSITIVE_ARG_KEYS.has(field.toLowerCase())) return "[REDACTED]";
463
470
  const value = args[field];
464
471
  if (value === undefined || value === null) return "<unknown>";
465
472
  if (typeof value === "string") return value;
@@ -34,8 +34,13 @@
34
34
  */
35
35
 
36
36
  /**
37
- * Argument keys whose values are secrets and must never appear in a preview.
38
- * Matched case-insensitively against the top-level key name.
37
+ * Argument keys whose values are secrets and must never appear in a preview,
38
+ * on a row's `args`, or in an approval message (stigmer#1119). Matched
39
+ * case-insensitively against the top-level key name. Clients mirror this set
40
+ * to hide the values on rows persisted before the runner redacted `args`
41
+ * (`@stigmer/sdk`'s `isSecretArgKey`); the shared, machine-checked contract is
42
+ * `test/fixtures/tool-view/secret-args.json` — keep this set and that fixture
43
+ * in lockstep.
39
44
  */
40
45
  export const SENSITIVE_ARG_KEYS: ReadonlySet<string> = new Set([
41
46
  "password", "token", "secret", "api_key", "apikey",
@@ -60,9 +65,11 @@ export const SALIENT_ARG_FIELDS = ["file_path", "path", "target_notebook", "comm
60
65
  /**
61
66
  * Redact secret-keyed values (see {@link SENSITIVE_ARG_KEYS}), preserving every
62
67
  * other entry verbatim. The first step of the preview builder, and the shape
63
- * stamped as `args` on a proposed row the harness recovered from its engine's
64
- * state (issue #754's header fix): full enough for the UI's path/primary-arg
65
- * extraction, never carrying a secret value.
68
+ * stamped as `args` on every row: by the transcript builder on every row with
69
+ * args (since stigmer#1119), and on a proposed row the harness recovered from
70
+ * its engine's state (issue #754's header fix). Full enough for the UI's
71
+ * path/primary-arg extraction and for exact-apply, never carrying a secret
72
+ * value.
66
73
  */
67
74
  export function redactSensitiveArgs(
68
75
  args: Record<string, unknown>,
@@ -27,6 +27,11 @@
27
27
  * ambient aws/gcloud auth), and on a local backend the shell can read the
28
28
  * credential files off disk regardless (owner ruling on #385).
29
29
  */
30
+ import {
31
+ TEMPORAL_API_KEY_ENV,
32
+ TEMPORAL_TLS_CLIENT_KEY_DATA_ENV,
33
+ } from "@stigmer/temporal-codecs";
34
+
30
35
  export const RUNNER_CREDENTIAL_ENV_KEYS: readonly string[] = [
31
36
  // Derives HITL approval fingerprints (fingerprint-secret.ts) — an agent
32
37
  // that reads this could forge approval receipts.
@@ -49,6 +54,13 @@ export const RUNNER_CREDENTIAL_ENV_KEYS: readonly string[] = [
49
54
  // Bedrock backend bearer credential, read by the AWS SDK's chain
50
55
  // (llm-backend.ts documents it as a supported auth path).
51
56
  "AWS_BEARER_TOKEN_BEDROCK",
57
+ // The Temporal frontend's API key and the mutual-TLS client key, read by
58
+ // the Temporal connection settings (@stigmer/temporal-codecs'
59
+ // connection config). Whoever holds either can reach Temporal as this
60
+ // runner. Stigmer's own names, never Temporal's TEMPORAL_API_KEY, which
61
+ // is the user's (that module's header).
62
+ TEMPORAL_API_KEY_ENV,
63
+ TEMPORAL_TLS_CLIENT_KEY_DATA_ENV,
52
64
  ];
53
65
 
54
66
  /**
package/src/worker.ts CHANGED
@@ -3,10 +3,8 @@
3
3
  *
4
4
  * Registers both activities and workflows on a single queue.
5
5
  *
6
- * Workflows:
7
- * - "stigmer/mcp-server/connect" — ConnectMcpServerWorkflow (discover + classify)
8
- * - "stigmer/mcp-server/discover" — Legacy discover-only workflow
9
- * - "stigmer/workflow/execute" — CNCF Serverless Workflow execution
6
+ * Workflows: exactly the types in `workflows/index.ts`, each started by
7
+ * the server with ids (that file's header is the list and the rule).
10
8
  *
11
9
  * Architecture:
12
10
  * - Java backend starts connect workflows on the runner's task queue
@@ -41,6 +39,7 @@ export async function startWorker(opts: StartWorkerOptions): Promise<Worker> {
41
39
 
42
40
  const connection = await NativeConnection.connect({
43
41
  address: config.temporalAddress,
42
+ ...config.temporalConnection,
44
43
  });
45
44
 
46
45
  const { createWorkflowMetricsSinks } = await import("./interceptors/workflow-metrics-sink.js");
@@ -79,6 +79,31 @@ describe("RunTaskBuilder", () => {
79
79
  const builder = new RunTaskBuilder("task", taskDef);
80
80
  expect(() => builder.build()).toThrow("workflow.name is required");
81
81
  });
82
+
83
+ it.each([
84
+ "stigmer/workflow/execute",
85
+ "stigmer/workflow/execute-from-execution",
86
+ "stigmer/mcp-server/connect",
87
+ "stigmer/mcp-server/discover",
88
+ "stigmer/agent-execution/invoke",
89
+ ])("refuses the platform workflow type %s", (name) => {
90
+ const taskDef: RunTaskDef = {
91
+ kind: "run",
92
+ run: { workflow: { name, namespace: "default", version: "1.0.0" } },
93
+ };
94
+ const builder = new RunTaskBuilder("reachIn", taskDef);
95
+ expect(() => builder.build()).toThrow(
96
+ `Run task 'reachIn': '${name}' is a platform workflow type, and a workflow cannot start one`,
97
+ );
98
+ });
99
+
100
+ it("admits a name that only mentions the platform outside the prefix", () => {
101
+ const taskDef: RunTaskDef = {
102
+ kind: "run",
103
+ run: { workflow: { name: "my-stigmer/child", namespace: "default", version: "1.0.0" } },
104
+ };
105
+ expect(() => new RunTaskBuilder("child", taskDef).build()).not.toThrow();
106
+ });
82
107
  });
83
108
 
84
109
  describe("script execution", () => {
@@ -7,7 +7,9 @@
7
7
  * - `run.workflow`: Child Temporal workflow (await or fire-and-forget)
8
8
  *
9
9
  * The kernel validates configuration and delegates to `ctx.runCommand`
10
- * (for script/shell) or `ctx.runWorkflow` (for child workflows).
10
+ * (for script/shell) or `ctx.runWorkflow` (for child workflows). A child
11
+ * workflow's name may not be a platform workflow type
12
+ * ({@link PLATFORM_WORKFLOW_TYPE_PREFIX} says why).
11
13
  *
12
14
  * YAML shapes:
13
15
  * - runScript:
@@ -42,6 +44,19 @@ import type {
42
44
 
43
45
  const SUPPORTED_LANGUAGES = ["js", "python"];
44
46
 
47
+ /**
48
+ * The namespace of the platform's own Temporal workflow types. A child
49
+ * started by `run.workflow` runs on the parent's task queue, which is a
50
+ * runner's queue, so the types a name can reach are exactly the ones a
51
+ * runner registers (`workflows/index.ts`): work the server never
52
+ * dispatched, outside the run it belongs to. A workflow therefore cannot
53
+ * name one. `workflows/__tests__/barrel.test.ts` pins that every registered
54
+ * type carries this prefix, so the refusal covers each. (Server types need
55
+ * not carry it, `schedule/tick` does not: they run on the server's own
56
+ * queues, which a child here never reaches.)
57
+ */
58
+ export const PLATFORM_WORKFLOW_TYPE_PREFIX = "stigmer/";
59
+
45
60
  export class RunTaskBuilder implements TaskBuilder {
46
61
  readonly taskName: string;
47
62
  readonly taskDef: TaskDef;
@@ -138,5 +153,10 @@ function validateRunConfig(config: RunConfig, taskName: string): void {
138
153
  if (!config.workflow.name) {
139
154
  throw new Error(`Run task '${taskName}': workflow.name is required`);
140
155
  }
156
+ if (config.workflow.name.startsWith(PLATFORM_WORKFLOW_TYPE_PREFIX)) {
157
+ throw new Error(
158
+ `Run task '${taskName}': '${config.workflow.name}' is a platform workflow type, and a workflow cannot start one`,
159
+ );
160
+ }
141
161
  }
142
162
  }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The fence on what a runner registers. Every export of `workflows/index.ts`
3
+ * is a Temporal workflow type on every worker root, and anyone who can
4
+ * reach Temporal can start any of them on a runner's queue. So the set is
5
+ * pinned exactly: the three types the server starts, each by id, none of
6
+ * which takes a model to run. A new export fails here until this list, and
7
+ * the review that comes with changing it, admits it.
8
+ *
9
+ * It also pins the link to the `run.workflow` refusal
10
+ * (`workflow-engine/tasks/run.ts`): every registered type carries
11
+ * `PLATFORM_WORKFLOW_TYPE_PREFIX`, so a workflow can never name one as its
12
+ * child. And it pins the test barrel (`src/__test-utils__/workflows/`) to
13
+ * the production set plus its one inline entry, under the name the tests
14
+ * start it by, since an export alias cannot import that constant.
15
+ */
16
+
17
+ import { describe, expect, it } from "vitest";
18
+
19
+ import * as barrel from "../index.js";
20
+ import * as testBarrel from "../../__test-utils__/workflows/index.js";
21
+ import { INLINE_MODEL_WORKFLOW_TYPE } from "../../__test-utils__/workflows/inline-model.js";
22
+ import { EXECUTE_FROM_EXECUTION_WORKFLOW_TYPE } from "../execute-from-execution.js";
23
+ import { PLATFORM_WORKFLOW_TYPE_PREFIX } from "../../workflow-engine/tasks/run.js";
24
+
25
+ describe("the registered workflow types", () => {
26
+ it("are exactly the types the server starts", () => {
27
+ expect(Object.keys(barrel).sort()).toEqual(
28
+ [
29
+ "stigmer/mcp-server/connect",
30
+ "stigmer/mcp-server/discover",
31
+ EXECUTE_FROM_EXECUTION_WORKFLOW_TYPE,
32
+ ].sort(),
33
+ );
34
+ });
35
+
36
+ it("include no type that runs a model handed to it", () => {
37
+ expect(Object.keys(barrel)).not.toContain("stigmer/workflow/execute");
38
+ });
39
+
40
+ it("all carry the platform prefix the run.workflow refusal checks", () => {
41
+ for (const type of Object.keys(barrel)) {
42
+ expect(type.startsWith(PLATFORM_WORKFLOW_TYPE_PREFIX), type).toBe(true);
43
+ }
44
+ });
45
+
46
+ it("are what the test barrel adds its inline entry to, outside the platform prefix", () => {
47
+ expect(Object.keys(testBarrel).sort()).toEqual(
48
+ [...Object.keys(barrel), INLINE_MODEL_WORKFLOW_TYPE].sort(),
49
+ );
50
+ expect(INLINE_MODEL_WORKFLOW_TYPE.startsWith(PLATFORM_WORKFLOW_TYPE_PREFIX)).toBe(false);
51
+ });
52
+ });
@@ -1,7 +1,19 @@
1
+ /**
2
+ * The workflow engine (`engine-core.ts`) driven with a materialized model,
3
+ * through the test harness's inline entry
4
+ * (`src/__test-utils__/workflows/inline-model.ts`), with the Temporal
5
+ * workflow API mocked. It pins the engine's behaviour: task output,
6
+ * workflow-level `input.from` and `output.as`, expression evaluation
7
+ * through the local activity, error handling, event sequences and flow
8
+ * directives. Production reaches the same engine only through the
9
+ * hydration workflow; `barrel.test.ts` pins that no production type takes
10
+ * a model from its caller.
11
+ */
12
+
1
13
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
14
  import { evaluateExpressionBatch } from "../../workflow-engine/expression.js";
3
15
  import type { WorkflowModel } from "../../workflow-engine/types.js";
4
- import type { ExecuteServerlessWorkflowInput } from "../execute-serverless-workflow.js";
16
+ import type { ExecuteServerlessWorkflowInput } from "../engine-core.js";
5
17
 
6
18
  const mockEvaluateExpressions = vi.fn();
7
19
  const mockResetEventSequence = vi.fn();
@@ -51,7 +63,7 @@ vi.mock("@temporalio/workflow", () => ({
51
63
  isCancellation: vi.fn(() => false),
52
64
  }));
53
65
 
54
- describe("executeServerlessWorkflow", () => {
66
+ describe("the engine, on a materialized model", () => {
55
67
  beforeEach(() => {
56
68
  vi.clearAllMocks();
57
69
  mockEvaluateExpressions.mockImplementation(
@@ -60,8 +72,8 @@ describe("executeServerlessWorkflow", () => {
60
72
  });
61
73
 
62
74
  async function runWorkflow(input: ExecuteServerlessWorkflowInput) {
63
- const { executeServerlessWorkflow } = await import("../execute-serverless-workflow.js");
64
- return executeServerlessWorkflow(input);
75
+ const { executeInlineModel } = await import("../../__test-utils__/workflows/inline-model.js");
76
+ return executeInlineModel(input);
65
77
  }
66
78
 
67
79
  describe("basic workflow execution", () => {
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * The workflow engine's CallAgentTaskBuilder (workflow-engine/tasks/
12
12
  * call-agent.ts) calls `ctx.callAgent()`, which is wired to
13
- * `orchestrateAgentCall()` in execute-serverless-workflow.ts.
13
+ * `orchestrateAgentCall()` in engine-core.ts.
14
14
  *
15
15
  * SANDBOX RULES: Only @temporalio/workflow imports, type-only imports,
16
16
  * and pure logic. No Node.js built-ins.
@@ -2,10 +2,13 @@
2
2
  * Shared workflow engine core — runs CNCF Serverless Workflow DSL
3
3
  * tasks inside the Temporal deterministic sandbox.
4
4
  *
5
- * Extracted from execute-serverless-workflow.ts so that both the
6
- * direct workflow ("stigmer/workflow/execute") and the hydration
7
- * wrapper ("stigmer/workflow/execute-from-execution") can share the
8
- * engine without code duplication.
5
+ * The engine runs a fully materialized {@link ExecuteServerlessWorkflowInput}
6
+ * and owns that type. Production reaches it only through the hydration
7
+ * workflow ("stigmer/workflow/execute-from-execution"), which reads the
8
+ * model, env and input back from the server by id; no registered workflow
9
+ * accepts a materialized model from its caller (see `index.ts`). The test
10
+ * harness runs goldens through an inline entry of its own
11
+ * (`src/__test-utils__/workflows/`).
9
12
  *
10
13
  * SANDBOX RULES: This file runs inside the Temporal deterministic V8
11
14
  * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
@@ -46,10 +49,9 @@ import type {
46
49
  HumanInputExecutionConfig,
47
50
  TaskExecutionContext,
48
51
  WorkflowEventDescriptor,
52
+ WorkflowModel,
49
53
  } from "../workflow-engine/types.js";
50
54
 
51
- import type { ExecuteServerlessWorkflowInput } from "./execute-serverless-workflow.js";
52
-
53
55
  // ─────────────────────────────────────────────────────────────────────────────
54
56
  // Activity Proxies (module-level singletons — shared across all workflow
55
57
  // invocations within the same worker)
@@ -132,6 +134,30 @@ const promoteProxy = proxyLocalActivities<PromoteActivities>({
132
134
  },
133
135
  });
134
136
 
137
+ // ─────────────────────────────────────────────────────────────────────────────
138
+ // Engine Input
139
+ // ─────────────────────────────────────────────────────────────────────────────
140
+
141
+ /**
142
+ * What the engine runs: a parsed model, the merged env and the workflow
143
+ * input. Built by the hydration activity from what the server holds
144
+ * (`activities/hydrate-workflow-execution.ts`), never taken from a caller.
145
+ */
146
+ export interface ExecuteServerlessWorkflowInput {
147
+ model: WorkflowModel;
148
+ workflow_input: unknown;
149
+ env: Record<string, unknown>;
150
+ metadata?: ExecutionMetadata;
151
+ }
152
+
153
+ export interface ExecutionMetadata {
154
+ execution_id?: string;
155
+ workflow_id?: string;
156
+ workflow_instance_id?: string;
157
+ org_id?: string;
158
+ execution_target?: number;
159
+ }
160
+
135
161
  // ─────────────────────────────────────────────────────────────────────────────
136
162
  // Engine Core
137
163
  // ─────────────────────────────────────────────────────────────────────────────
@@ -149,9 +175,8 @@ export interface RunWorkflowEngineOptions {
149
175
  * executes all tasks via {@link executeDoTasks}, and returns the final
150
176
  * output.
151
177
  *
152
- * Called by both:
153
- * - `executeServerlessWorkflow` (direct invocation with pre-materialized input)
154
- * - `executeFromExecution` (wrapper that hydrates from slim IDs first)
178
+ * Called by `executeFromExecution` once it has hydrated the input from
179
+ * slim ids, and by the test harness's inline entry.
155
180
  *
156
181
  * @param options.checkPause Optional pause yield point callback. When
157
182
  * provided, the engine calls this between tasks and allows the
@@ -1,13 +1,29 @@
1
1
  /**
2
- * Workflow barrel file — the entry point for Temporal's workflow bundler.
2
+ * Workflow barrel file — the entry point for Temporal's workflow bundler,
3
+ * and the complete list of workflow types a runner registers.
3
4
  *
4
5
  * Re-exports workflow functions with the exact Temporal workflow type
5
- * names that the Java/Go backend uses to start them. The Temporal TS
6
- * SDK derives the workflow type from the export name of the module
7
- * passed to `workflowsPath`.
6
+ * names that the server uses to start them. The Temporal TS SDK derives
7
+ * the workflow type from the export name of the module passed to
8
+ * `workflowsPath`, so every export here is a registered type on every
9
+ * worker root: the static worker, the manager and pool workers, and the
10
+ * pre-built bundle (`scripts/bundle-slim.mjs`).
8
11
  *
9
- * The Java backend starts workflows via:
10
- * workflowClient.newUntypedWorkflowStub("stigmer/mcp-server/connect", ...)
12
+ * THE RULE: every export is a type the server starts, and each takes ids
13
+ * that the runner reads back from the server, never a model to run.
14
+ * Anyone who can reach Temporal can start any type registered here on a
15
+ * runner's queue, so a new export is a new door and is reviewed as a
16
+ * wire change. `__tests__/barrel.test.ts` pins the exact set. Tests that
17
+ * hand the engine a model directly use the test barrel
18
+ * (`src/__test-utils__/workflows/index.ts`).
19
+ *
20
+ * The types and their starters:
21
+ * - "stigmer/mcp-server/connect" and "stigmer/mcp-server/discover": the
22
+ * server's MCP connect lane (`temporal/mcpserver/names.ts` in the
23
+ * server), by MCP server id.
24
+ * - "stigmer/workflow/execute-from-execution": the server's workflow
25
+ * execution orchestrator (`temporal/workflowexecution/names.ts`), by
26
+ * execution id; it hydrates the model from the server.
11
27
  *
12
28
  * ES2022 arbitrary module export names (`export { fn as "..." }`) let
13
29
  * us map TypeScript function names to the slash-delimited Temporal
@@ -26,10 +42,6 @@ export {
26
42
  discoverMcpServerLegacy as "stigmer/mcp-server/discover",
27
43
  } from "./connect-mcp-server.js";
28
44
 
29
- export {
30
- executeServerlessWorkflow as "stigmer/workflow/execute",
31
- } from "./execute-serverless-workflow.js";
32
-
33
45
  export {
34
46
  executeFromExecution as "stigmer/workflow/execute-from-execution",
35
47
  } from "./execute-from-execution.js";
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Shared pause/resume signal definitions and handler setup for
3
- * workflow execution. Used by both the hydration wrapper
4
- * ("stigmer/workflow/execute-from-execution") and the direct
5
- * invocation path ("stigmer/workflow/execute").
3
+ * workflow execution. Used by the hydration wrapper
4
+ * ("stigmer/workflow/execute-from-execution") and by the test harness's
5
+ * inline entry (`src/__test-utils__/workflows/inline-model.ts`).
6
6
  *
7
7
  * The Java/Go orchestrators forward pause and resume signals to
8
8
  * the child workflow. The engine checks a `checkPause` callback
@@ -1,32 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
- import type { WorkflowModel } from "../workflow-engine/types.js";
19
- export interface ExecuteServerlessWorkflowInput {
20
- model: WorkflowModel;
21
- workflow_input: unknown;
22
- env: Record<string, unknown>;
23
- metadata?: ExecutionMetadata;
24
- }
25
- export interface ExecutionMetadata {
26
- execution_id?: string;
27
- workflow_id?: string;
28
- workflow_instance_id?: string;
29
- org_id?: string;
30
- execution_target?: number;
31
- }
32
- export declare function executeServerlessWorkflow(input: ExecuteServerlessWorkflowInput): Promise<unknown>;
@@ -1,36 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
- import { isCancellation } from "@temporalio/workflow";
19
- import { runWorkflowEngine } from "./engine-core.js";
20
- import { setupPauseResumeHandlers } from "./workflow-signals.js";
21
- // ─────────────────────────────────────────────────────────────────────────────
22
- // Workflow Function
23
- // ─────────────────────────────────────────────────────────────────────────────
24
- export async function executeServerlessWorkflow(input) {
25
- const { checkPause } = setupPauseResumeHandlers();
26
- try {
27
- return await runWorkflowEngine(input, { checkPause });
28
- }
29
- catch (err) {
30
- if (isCancellation(err)) {
31
- // Let CancelledFailure propagate — parent handles cleanup
32
- }
33
- throw err;
34
- }
35
- }
36
- //# sourceMappingURL=execute-serverless-workflow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"execute-serverless-workflow.js","sourceRoot":"","sources":["../../src/workflows/execute-serverless-workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAqBjE,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAqC;IAErC,MAAM,EAAE,UAAU,EAAE,GAAG,wBAAwB,EAAE,CAAC;IAElD,IAAI,CAAC;QACH,OAAO,MAAM,iBAAiB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,0DAA0D;QAC5D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -1,60 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
-
19
- import { isCancellation } from "@temporalio/workflow";
20
- import type { WorkflowModel } from "../workflow-engine/types.js";
21
- import { runWorkflowEngine } from "./engine-core.js";
22
- import { setupPauseResumeHandlers } from "./workflow-signals.js";
23
-
24
- // ─────────────────────────────────────────────────────────────────────────────
25
- // Workflow Input/Output Types
26
- // ─────────────────────────────────────────────────────────────────────────────
27
-
28
- export interface ExecuteServerlessWorkflowInput {
29
- model: WorkflowModel;
30
- workflow_input: unknown;
31
- env: Record<string, unknown>;
32
- metadata?: ExecutionMetadata;
33
- }
34
-
35
- export interface ExecutionMetadata {
36
- execution_id?: string;
37
- workflow_id?: string;
38
- workflow_instance_id?: string;
39
- org_id?: string;
40
- execution_target?: number;
41
- }
42
-
43
- // ─────────────────────────────────────────────────────────────────────────────
44
- // Workflow Function
45
- // ─────────────────────────────────────────────────────────────────────────────
46
-
47
- export async function executeServerlessWorkflow(
48
- input: ExecuteServerlessWorkflowInput,
49
- ): Promise<unknown> {
50
- const { checkPause } = setupPauseResumeHandlers();
51
-
52
- try {
53
- return await runWorkflowEngine(input, { checkPause });
54
- } catch (err) {
55
- if (isCancellation(err)) {
56
- // Let CancelledFailure propagate — parent handles cleanup
57
- }
58
- throw err;
59
- }
60
- }