@stigmer/runner 3.12.7 → 3.12.9

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 (79) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/execute-cursor/fetch-interceptor.js +29 -16
  3. package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
  4. package/dist/activities/execute-cursor/index.d.ts +14 -0
  5. package/dist/activities/execute-cursor/index.js +76 -5
  6. package/dist/activities/execute-cursor/index.js.map +1 -1
  7. package/dist/activities/execute-cursor/message-translator.d.ts +15 -9
  8. package/dist/activities/execute-cursor/message-translator.js +15 -9
  9. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  10. package/dist/activities/execute-deep-agent/index.js +9 -0
  11. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  12. package/dist/activities/execute-deep-agent/mcp-gate.d.ts +2 -0
  13. package/dist/activities/execute-deep-agent/mcp-gate.js +2 -1
  14. package/dist/activities/execute-deep-agent/mcp-gate.js.map +1 -1
  15. package/dist/activities/execute-deep-agent/setup.d.ts +10 -1
  16. package/dist/activities/execute-deep-agent/setup.js +45 -3
  17. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  18. package/dist/payload-codecs.d.ts +1 -1
  19. package/dist/payload-codecs.js +6 -4
  20. package/dist/payload-codecs.js.map +1 -1
  21. package/dist/shared/memory-attachment.d.ts +97 -0
  22. package/dist/shared/memory-attachment.js +136 -0
  23. package/dist/shared/memory-attachment.js.map +1 -0
  24. package/dist/shared/memory-retrieval.d.ts +126 -0
  25. package/dist/shared/memory-retrieval.js +293 -0
  26. package/dist/shared/memory-retrieval.js.map +1 -0
  27. package/dist/shared/runner-credential-keys.js +2 -1
  28. package/dist/shared/runner-credential-keys.js.map +1 -1
  29. package/dist/shared/tool-kind.js +9 -0
  30. package/dist/shared/tool-kind.js.map +1 -1
  31. package/package.json +3 -2
  32. package/src/__tests__/history-encryption-e2e.test.ts +1 -1
  33. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -1
  34. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +49 -15
  35. package/src/activities/execute-cursor/fetch-interceptor.ts +37 -16
  36. package/src/activities/execute-cursor/index.ts +86 -5
  37. package/src/activities/execute-cursor/message-translator.ts +15 -9
  38. package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +7 -0
  39. package/src/activities/execute-deep-agent/index.ts +10 -0
  40. package/src/activities/execute-deep-agent/mcp-gate.ts +4 -1
  41. package/src/activities/execute-deep-agent/setup.ts +70 -6
  42. package/src/payload-codecs.ts +12 -9
  43. package/src/shared/__tests__/memory-attachment.test.ts +167 -0
  44. package/src/shared/__tests__/memory-retrieval.test.ts +310 -0
  45. package/src/shared/memory-attachment.ts +167 -0
  46. package/src/shared/memory-retrieval.ts +383 -0
  47. package/src/shared/runner-credential-keys.ts +2 -1
  48. package/src/shared/tool-kind.ts +10 -0
  49. package/dist/claimcheck/compressor.d.ts +0 -2
  50. package/dist/claimcheck/compressor.js +0 -8
  51. package/dist/claimcheck/compressor.js.map +0 -1
  52. package/dist/claimcheck/config.d.ts +0 -7
  53. package/dist/claimcheck/config.js +0 -10
  54. package/dist/claimcheck/config.js.map +0 -1
  55. package/dist/claimcheck/index.d.ts +0 -3
  56. package/dist/claimcheck/index.js +0 -4
  57. package/dist/claimcheck/index.js.map +0 -1
  58. package/dist/claimcheck/payload-codec.d.ts +0 -23
  59. package/dist/claimcheck/payload-codec.js +0 -105
  60. package/dist/claimcheck/payload-codec.js.map +0 -1
  61. package/dist/encryption/config.d.ts +0 -64
  62. package/dist/encryption/config.js +0 -113
  63. package/dist/encryption/config.js.map +0 -1
  64. package/dist/encryption/index.d.ts +0 -3
  65. package/dist/encryption/index.js +0 -3
  66. package/dist/encryption/index.js.map +0 -1
  67. package/dist/encryption/payload-codec.d.ts +0 -41
  68. package/dist/encryption/payload-codec.js +0 -130
  69. package/dist/encryption/payload-codec.js.map +0 -1
  70. package/src/__tests__/claimcheck-codec.test.ts +0 -256
  71. package/src/__tests__/encryption-codec.test.ts +0 -287
  72. package/src/__tests__/fixtures/encrypted-payload-fixture.json +0 -15
  73. package/src/claimcheck/compressor.ts +0 -9
  74. package/src/claimcheck/config.ts +0 -20
  75. package/src/claimcheck/index.ts +0 -3
  76. package/src/claimcheck/payload-codec.ts +0 -139
  77. package/src/encryption/config.ts +0 -161
  78. package/src/encryption/index.ts +0 -3
  79. package/src/encryption/payload-codec.ts +0 -152
@@ -1,152 +0,0 @@
1
- /**
2
- * Temporal PayloadCodec that encrypts payloads at rest in workflow
3
- * history (stigmer-cloud#227).
4
- *
5
- * Why: the workflow engine runs inside the Temporal deterministic
6
- * sandbox, so decrypted execution-context values cross the history
7
- * boundary in many places — the hydrate activity result, the runtime
8
- * env passed as an input to every per-task activity, and expression
9
- * results recorded as local-activity markers. Encrypting at the payload
10
- * codec layer closes the entire class with one mechanism instead of
11
- * chasing each crossing.
12
- *
13
- * Envelope (cross-SDK contract — the Java decode-only codec in
14
- * stigmer-cloud's temporal-starter must match it byte-for-byte, pinned
15
- * by the conformance fixture in __tests__/fixtures/):
16
- *
17
- * metadata: encoding = "binary/encrypted"
18
- * encryption-key-id = <key id that encrypted this payload>
19
- * data: iv (12 bytes) ‖ AES-256-GCM(ciphertext ‖ tag (16 bytes))
20
- *
21
- * The plaintext is the serialized ORIGINAL Payload proto (metadata AND
22
- * data), so decode restores the payload exactly — including its
23
- * original encoding — with no side channel.
24
- *
25
- * Decode passes through payloads it did not encode. This is what keeps
26
- * plaintext signals from the Java/Go orchestrators and pre-rollout
27
- * in-flight histories working with zero migration. Everything else
28
- * fails closed: unknown key id, missing key id, and ciphertext tampering
29
- * all throw rather than surfacing bogus payloads.
30
- */
31
-
32
- import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
33
- import type { Payload, PayloadCodec } from "@temporalio/common";
34
- // Default-import + destructure, NOT `import { temporal } from …`:
35
- // @temporalio/proto is CommonJS and its `temporal` export defeats Node's
36
- // cjs-module-lexer named-export detection, so the named form loads under
37
- // tsx/vitest (their interop is looser) but crashes plain `node dist/main.js`
38
- // at startup with "Named export 'temporal' not found" (stigmer/stigmer#399
39
- // boot regression). Pinned by scripts/verify-dist-boot.mjs in CI.
40
- import proto from "@temporalio/proto";
41
- import type { EncryptionKey, PayloadEncryptionConfig } from "./config.js";
42
-
43
- const { temporal } = proto;
44
-
45
- const ENCODING_METADATA_KEY = "encoding";
46
- const ENCRYPTED_ENCODING_VALUE = "binary/encrypted";
47
- const KEY_ID_METADATA_KEY = "encryption-key-id";
48
-
49
- /** AES-GCM parameters shared with the Java implementation. */
50
- const IV_BYTES = 12;
51
- const AUTH_TAG_BYTES = 16;
52
-
53
- export class EncryptionPayloadCodec implements PayloadCodec {
54
- private readonly decryptKeysById: Map<string, Buffer>;
55
-
56
- constructor(private readonly config: PayloadEncryptionConfig) {
57
- this.decryptKeysById = new Map([[config.primary.keyId, config.primary.key]]);
58
- if (config.secondary) {
59
- this.decryptKeysById.set(config.secondary.keyId, config.secondary.key);
60
- }
61
- }
62
-
63
- async encode(payloads: Payload[]): Promise<Payload[]> {
64
- return payloads.map((p) => this.encodePayload(p));
65
- }
66
-
67
- async decode(payloads: Payload[]): Promise<Payload[]> {
68
- return payloads.map((p) => this.decodePayload(p));
69
- }
70
-
71
- private encodePayload(payload: Payload): Payload {
72
- // Data-less payloads (binary/null from void results) stay as-is:
73
- // there is nothing to protect, and the cross-language parents that
74
- // await our workflows as void must be able to read them without a key.
75
- if (!payload.data || payload.data.length === 0) {
76
- return payload;
77
- }
78
-
79
- const plaintext = temporal.api.common.v1.Payload.encode(payload).finish();
80
- return {
81
- metadata: {
82
- [ENCODING_METADATA_KEY]: Buffer.from(ENCRYPTED_ENCODING_VALUE),
83
- [KEY_ID_METADATA_KEY]: Buffer.from(this.config.primary.keyId),
84
- },
85
- data: encrypt(plaintext, this.config.primary),
86
- };
87
- }
88
-
89
- private decodePayload(payload: Payload): Payload {
90
- if (!isEncryptedPayload(payload)) {
91
- return payload;
92
- }
93
-
94
- const keyIdBytes = payload.metadata?.[KEY_ID_METADATA_KEY];
95
- if (!keyIdBytes) {
96
- throw new Error(
97
- "Encrypted payload is missing its encryption-key-id metadata — refusing to decode",
98
- );
99
- }
100
- const keyId = Buffer.from(keyIdBytes).toString("utf-8");
101
- const key = this.decryptKeysById.get(keyId);
102
- if (!key) {
103
- throw new Error(
104
- `Encrypted payload uses unknown key id '${keyId}' — configure it as the ` +
105
- `primary or secondary payload encryption key (rotation window?)`,
106
- );
107
- }
108
-
109
- const plaintext = decrypt(payload.data!, key, keyId);
110
- return temporal.api.common.v1.Payload.decode(plaintext);
111
- }
112
- }
113
-
114
- function isEncryptedPayload(payload: Payload): boolean {
115
- const encoding = payload.metadata?.[ENCODING_METADATA_KEY];
116
- if (!encoding) return false;
117
- return Buffer.from(encoding).toString("utf-8") === ENCRYPTED_ENCODING_VALUE;
118
- }
119
-
120
- function encrypt(plaintext: Uint8Array, key: EncryptionKey): Buffer {
121
- const iv = randomBytes(IV_BYTES);
122
- const cipher = createCipheriv("aes-256-gcm", key.key, iv);
123
- const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
124
- // Layout iv ‖ ciphertext ‖ tag matches Java's AES/GCM/NoPadding, whose
125
- // doFinal() output is ciphertext ‖ tag.
126
- return Buffer.concat([iv, ciphertext, cipher.getAuthTag()]);
127
- }
128
-
129
- function decrypt(data: Uint8Array, key: Buffer, keyId: string): Buffer {
130
- if (data.length < IV_BYTES + AUTH_TAG_BYTES) {
131
- throw new Error(
132
- `Encrypted payload under key id '${keyId}' is truncated (${data.length} bytes)`,
133
- );
134
- }
135
- const buf = Buffer.from(data);
136
- const iv = buf.subarray(0, IV_BYTES);
137
- const ciphertext = buf.subarray(IV_BYTES, buf.length - AUTH_TAG_BYTES);
138
- const tag = buf.subarray(buf.length - AUTH_TAG_BYTES);
139
-
140
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
141
- decipher.setAuthTag(tag);
142
- try {
143
- return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
144
- } catch {
145
- // GCM auth failure: tampered ciphertext or a key that does not match
146
- // its advertised id. Never surface partially decrypted bytes.
147
- throw new Error(
148
- `Failed to decrypt payload under key id '${keyId}' — ciphertext is ` +
149
- `corrupt or the configured key does not match`,
150
- );
151
- }
152
- }