@pikku/core 0.12.137 → 0.12.138
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 +31 -0
- package/dist/dev/hot-reload.js +5 -2
- package/dist/env.d.ts +18 -0
- package/dist/env.js +60 -1
- package/dist/function/abort-scope.d.ts +6 -5
- package/dist/function/abort-scope.js +6 -17
- package/dist/function/function-runner.js +2 -1
- package/dist/middleware/auth-apikey.js +1 -1
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/schema.js +3 -1
- package/dist/services/in-memory-queue-service.js +4 -2
- package/dist/services/in-memory-workflow-service.js +7 -6
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/services/local-variables.d.ts +5 -0
- package/dist/services/local-variables.js +7 -2
- package/dist/services/queue-webhook-service.js +1 -1
- package/dist/services/webhook-service.d.ts +2 -2
- package/dist/services/webhook-service.js +6 -4
- package/dist/types/core.types.d.ts +10 -1
- package/dist/utils/hmac.d.ts +25 -10
- package/dist/utils/hmac.js +202 -24
- package/dist/wirings/agent/agent-agui.js +65 -62
- package/dist/wirings/agent/agent-interrupt.d.ts +4 -1
- package/dist/wirings/agent/agent-interrupt.js +3 -3
- package/dist/wirings/agent/agent-memory.js +5 -6
- package/dist/wirings/agent/agent-model-config.js +2 -1
- package/dist/wirings/agent/agent-prepare.js +21 -13
- package/dist/wirings/agent/agent-stream.js +38 -34
- package/dist/wirings/agent/agent.types.d.ts +8 -1
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/local/local-channel-handler.js +5 -1
- package/dist/wirings/channel/local/local-channel-runner.js +6 -4
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +1 -0
- package/dist/wirings/channel/local/local-eventhub-service.js +4 -1
- package/dist/wirings/cli/channel/cli-channel-runner.js +7 -2
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +8 -4
- package/dist/wirings/cli/cli-runner.js +1 -1
- package/dist/wirings/gateway/gateway-runner.js +3 -3
- package/dist/wirings/http/http-runner.js +6 -6
- package/dist/wirings/scheduler/scheduler-runner.js +1 -1
- package/dist/wirings/scope/define-scope.d.ts +19 -0
- package/dist/wirings/scope/define-scope.js +19 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/trigger/trigger-runner.js +3 -1
- package/dist/wirings/trigger/webhook-source-runner.js +5 -2
- package/dist/wirings/virtual-user/virtual-user-scaffold.js +3 -2
- package/dist/wirings/workflow/workflow-invocation-id.js +85 -8
- package/package.json +3 -1
- package/src/public-surface.json +6 -3
|
@@ -43,7 +43,9 @@ export async function setupTrigger({ name, input, onTrigger, }) {
|
|
|
43
43
|
trigger: {
|
|
44
44
|
invoke: (data) => {
|
|
45
45
|
singletonServices.logger.info(`Trigger fired: ${name}`);
|
|
46
|
-
|
|
46
|
+
// `invoke` is typed void for trigger sources, so a rejection from the
|
|
47
|
+
// trigger function is logged here rather than left unhandled.
|
|
48
|
+
Promise.resolve(onTrigger(data)).catch((e) => singletonServices.logger.error(`Trigger '${name}' handler failed: ${e?.message ?? e}`));
|
|
47
49
|
},
|
|
48
50
|
},
|
|
49
51
|
};
|
|
@@ -63,6 +63,9 @@ const readRequest = async (http) => {
|
|
|
63
63
|
};
|
|
64
64
|
};
|
|
65
65
|
const signedWith = async (verify, request, secret, services) => {
|
|
66
|
+
// Fail closed: an empty secret never verifies, whatever the scheme.
|
|
67
|
+
if (!secret)
|
|
68
|
+
return false;
|
|
66
69
|
if (typeof verify === 'function') {
|
|
67
70
|
return await verify(request, secret, services);
|
|
68
71
|
}
|
|
@@ -72,14 +75,14 @@ const signedWith = async (verify, request, secret, services) => {
|
|
|
72
75
|
};
|
|
73
76
|
if ('hmac' in verify) {
|
|
74
77
|
const { header: name, prefix, algorithm, encoding, secretEncoding, } = verify.hmac;
|
|
75
|
-
return verifyHmacSignature(secret, header(name, prefix), algorithm, request.body, encoding, secretEncoding);
|
|
78
|
+
return await verifyHmacSignature(secret, header(name, prefix), algorithm, request.body, encoding, secretEncoding);
|
|
76
79
|
}
|
|
77
80
|
if ('token' in verify) {
|
|
78
81
|
const token = header(verify.token.header, verify.token.prefix);
|
|
79
82
|
return !!token && timingSafeStringEqual(token, secret);
|
|
80
83
|
}
|
|
81
84
|
const { header: name, ...options } = verify.publicKey;
|
|
82
|
-
return verifyPublicKeySignature(secret, header(name), request.body, options);
|
|
85
|
+
return await verifyPublicKeySignature(secret, header(name), request.body, options);
|
|
83
86
|
};
|
|
84
87
|
/**
|
|
85
88
|
* Whether the request was signed with the source's secret. A request with a
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readEnvVariable } from '../../env.js';
|
|
1
2
|
import { BadRequestError, ForbiddenError } from '../../errors/errors.js';
|
|
2
3
|
import { prepareVirtualUserRun } from './prepare-virtual-user-run.js';
|
|
3
4
|
import { runVirtualUser as runVirtualUserEngine } from './run-virtual-user.js';
|
|
@@ -122,7 +123,7 @@ const refuseInProduction = (personaId, disposition, config, environments, enviro
|
|
|
122
123
|
* scheduled tick have in common. The dispatch that follows is typed off the
|
|
123
124
|
* app's RPC map, so it stays in the generated wiring.
|
|
124
125
|
*/
|
|
125
|
-
export const startVirtualUserRun = async ({ store, personas, config, environments, environment =
|
|
126
|
+
export const startVirtualUserRun = async ({ store, personas, config, environments, environment = readEnvVariable('PIKKU_ENV'), persona: personaId, disposition: requested, seed: requestedSeed, goals, memory, startedBy, }) => {
|
|
126
127
|
const runStore = requireVirtualUserRunStore(store);
|
|
127
128
|
const persona = runnablePersona(personas, personaId);
|
|
128
129
|
const disposition = (requested ??
|
|
@@ -251,7 +252,7 @@ export const serializeVirtualUserSchedule = (schedule, personas) => {
|
|
|
251
252
|
* keeps what it had: enabling a row saved earlier as adversarial is refused
|
|
252
253
|
* just as saving one would be.
|
|
253
254
|
*/
|
|
254
|
-
export const writeVirtualUserSchedule = async ({ store, personas, persona, enabled, disposition, goals, budget, minIntervalMs, maxIntervalMs, nextRunAt, config, environments, environment =
|
|
255
|
+
export const writeVirtualUserSchedule = async ({ store, personas, persona, enabled, disposition, goals, budget, minIntervalMs, maxIntervalMs, nextRunAt, config, environments, environment = readEnvVariable('PIKKU_ENV'), }) => {
|
|
255
256
|
const scheduleStore = requireVirtualUserScheduleStore(store);
|
|
256
257
|
const declared = runnablePersona(personas, persona);
|
|
257
258
|
const current = enabled === undefined || disposition === undefined
|
|
@@ -1,16 +1,93 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
const PIKKU_WORKFLOW_NAMESPACE = '70696b6b-7500-5770-9f6c-6f77000a0001';
|
|
3
|
-
const
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
const parseUuid = (uuid) => {
|
|
4
|
+
const hex = uuid.replace(/-/g, '');
|
|
5
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
6
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
7
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
8
|
+
}
|
|
9
|
+
return bytes;
|
|
10
|
+
};
|
|
4
11
|
const formatUuid = (bytes) => {
|
|
5
|
-
|
|
12
|
+
let hex = '';
|
|
13
|
+
for (const b of bytes)
|
|
14
|
+
hex += b.toString(16).padStart(2, '0');
|
|
6
15
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
7
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* SHA-1 (FIPS 180-4). Web Crypto only offers an async digest and `uuidv5` is
|
|
19
|
+
* called synchronously (and is a public export), so this is a small pure-JS
|
|
20
|
+
* one. It only derives dedupe IDs, never anything secret.
|
|
21
|
+
*/
|
|
22
|
+
const sha1 = (message) => {
|
|
23
|
+
const padded = new Uint8Array(((message.length + 9 + 63) >> 6) << 6);
|
|
24
|
+
padded.set(message);
|
|
25
|
+
padded[message.length] = 0x80;
|
|
26
|
+
const view = new DataView(padded.buffer);
|
|
27
|
+
view.setUint32(padded.length - 8, Math.floor((message.length * 8) / 2 ** 32));
|
|
28
|
+
view.setUint32(padded.length - 4, (message.length * 8) >>> 0);
|
|
29
|
+
let h0 = 0x67452301;
|
|
30
|
+
let h1 = 0xefcdab89;
|
|
31
|
+
let h2 = 0x98badcfe;
|
|
32
|
+
let h3 = 0x10325476;
|
|
33
|
+
let h4 = 0xc3d2e1f0;
|
|
34
|
+
const w = new Uint32Array(80);
|
|
35
|
+
const rotl = (x, n) => (x << n) | (x >>> (32 - n));
|
|
36
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
37
|
+
for (let i = 0; i < 16; i++)
|
|
38
|
+
w[i] = view.getUint32(offset + i * 4);
|
|
39
|
+
for (let i = 16; i < 80; i++) {
|
|
40
|
+
w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
|
|
41
|
+
}
|
|
42
|
+
let a = h0;
|
|
43
|
+
let b = h1;
|
|
44
|
+
let c = h2;
|
|
45
|
+
let d = h3;
|
|
46
|
+
let e = h4;
|
|
47
|
+
for (let i = 0; i < 80; i++) {
|
|
48
|
+
let f;
|
|
49
|
+
let k;
|
|
50
|
+
if (i < 20) {
|
|
51
|
+
f = (b & c) | (~b & d);
|
|
52
|
+
k = 0x5a827999;
|
|
53
|
+
}
|
|
54
|
+
else if (i < 40) {
|
|
55
|
+
f = b ^ c ^ d;
|
|
56
|
+
k = 0x6ed9eba1;
|
|
57
|
+
}
|
|
58
|
+
else if (i < 60) {
|
|
59
|
+
f = (b & c) | (b & d) | (c & d);
|
|
60
|
+
k = 0x8f1bbcdc;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
f = b ^ c ^ d;
|
|
64
|
+
k = 0xca62c1d6;
|
|
65
|
+
}
|
|
66
|
+
const temp = (rotl(a, 5) + f + e + k + w[i]) >>> 0;
|
|
67
|
+
e = d;
|
|
68
|
+
d = c;
|
|
69
|
+
c = rotl(b, 30) >>> 0;
|
|
70
|
+
b = a;
|
|
71
|
+
a = temp;
|
|
72
|
+
}
|
|
73
|
+
h0 = (h0 + a) >>> 0;
|
|
74
|
+
h1 = (h1 + b) >>> 0;
|
|
75
|
+
h2 = (h2 + c) >>> 0;
|
|
76
|
+
h3 = (h3 + d) >>> 0;
|
|
77
|
+
h4 = (h4 + e) >>> 0;
|
|
78
|
+
}
|
|
79
|
+
const out = new Uint8Array(20);
|
|
80
|
+
const outView = new DataView(out.buffer);
|
|
81
|
+
[h0, h1, h2, h3, h4].forEach((h, i) => outView.setUint32(i * 4, h));
|
|
82
|
+
return out;
|
|
83
|
+
};
|
|
8
84
|
export const uuidv5 = (name, namespace = PIKKU_WORKFLOW_NAMESPACE) => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
85
|
+
const ns = parseUuid(namespace);
|
|
86
|
+
const nameBytes = encoder.encode(name);
|
|
87
|
+
const input = new Uint8Array(ns.length + nameBytes.length);
|
|
88
|
+
input.set(ns);
|
|
89
|
+
input.set(nameBytes, ns.length);
|
|
90
|
+
const bytes = sha1(input).subarray(0, 16);
|
|
14
91
|
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
15
92
|
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
16
93
|
return formatUuid(bytes);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.138",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/pikkujs/pikku.git",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"./services/local-content": "./dist/services/local-content.js",
|
|
82
82
|
"./services/local-content-request-handler": "./dist/services/local-content-request-handler.js",
|
|
83
83
|
"./services/temporary-file-service": "./dist/services/temporary-file-service.js",
|
|
84
|
+
"./services/file-scenario-run-store": "./dist/services/file-scenario-run-store.js",
|
|
84
85
|
"./crypto-utils": "./dist/crypto-utils.js",
|
|
85
86
|
"./hmac": "./dist/utils/hmac.js",
|
|
86
87
|
"./state": "./dist/pikku-state.js",
|
|
@@ -100,6 +101,7 @@
|
|
|
100
101
|
},
|
|
101
102
|
"devDependencies": {
|
|
102
103
|
"@ag-ui/core": "0.0.57",
|
|
104
|
+
"@pikku/deploy": "^0.12.15",
|
|
103
105
|
"@types/node": "^24.13.3",
|
|
104
106
|
"esbuild": "~0.28.2",
|
|
105
107
|
"tsx": "^4.23.12"
|
package/src/public-surface.json
CHANGED
|
@@ -326,6 +326,7 @@
|
|
|
326
326
|
"validateAndBuildCredentialDefinitionsMeta"
|
|
327
327
|
],
|
|
328
328
|
"./scope": [
|
|
329
|
+
"declareScopes",
|
|
329
330
|
"defineScope",
|
|
330
331
|
"flattenScopeDefinitions",
|
|
331
332
|
"hasScopes",
|
|
@@ -432,7 +433,6 @@
|
|
|
432
433
|
"ACTOR_SECRET_NAME",
|
|
433
434
|
"ConsoleLogger",
|
|
434
435
|
"DEFAULT_WEBHOOK_RETRIES",
|
|
435
|
-
"FileScenarioRunStore",
|
|
436
436
|
"InMemoryAgentRunStateService",
|
|
437
437
|
"InMemoryLeaseService",
|
|
438
438
|
"InMemoryQueueService",
|
|
@@ -482,8 +482,6 @@
|
|
|
482
482
|
"pikkuRemoteScheduledJobFunc",
|
|
483
483
|
"pikkuWebhookWorkerFunc",
|
|
484
484
|
"renderEmail",
|
|
485
|
-
"scenarioArtifactContentType",
|
|
486
|
-
"scenarioRunSummary",
|
|
487
485
|
"spy",
|
|
488
486
|
"stub",
|
|
489
487
|
"verifyActorSecret",
|
|
@@ -510,6 +508,11 @@
|
|
|
510
508
|
"createLocalContentRequestHandler",
|
|
511
509
|
"verifySignedContentRequest"
|
|
512
510
|
],
|
|
511
|
+
"./services/file-scenario-run-store": [
|
|
512
|
+
"FileScenarioRunStore",
|
|
513
|
+
"scenarioArtifactContentType",
|
|
514
|
+
"scenarioRunSummary"
|
|
515
|
+
],
|
|
513
516
|
"./services/temporary-file-service": [
|
|
514
517
|
"TemporaryFileInstance",
|
|
515
518
|
"TemporaryFileService"
|