keystone-cli 2.0.0 → 2.1.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 (57) hide show
  1. package/README.md +43 -4
  2. package/package.json +4 -1
  3. package/src/cli.ts +1 -0
  4. package/src/commands/event.ts +9 -0
  5. package/src/commands/run.ts +17 -0
  6. package/src/db/dynamic-state-manager.ts +12 -9
  7. package/src/db/memory-db.test.ts +19 -1
  8. package/src/db/memory-db.ts +101 -22
  9. package/src/db/workflow-db.ts +181 -9
  10. package/src/expression/evaluator.ts +4 -1
  11. package/src/parser/config-schema.ts +6 -0
  12. package/src/parser/schema.ts +1 -0
  13. package/src/runner/__test__/llm-test-setup.ts +43 -11
  14. package/src/runner/durable-timers.test.ts +1 -1
  15. package/src/runner/executors/dynamic-executor.ts +125 -88
  16. package/src/runner/executors/engine-executor.ts +10 -39
  17. package/src/runner/executors/file-executor.ts +67 -0
  18. package/src/runner/executors/foreach-executor.ts +170 -17
  19. package/src/runner/executors/human-executor.ts +18 -0
  20. package/src/runner/executors/llm/stream-handler.ts +103 -0
  21. package/src/runner/executors/llm/tool-manager.ts +360 -0
  22. package/src/runner/executors/llm-executor.ts +288 -555
  23. package/src/runner/executors/memory-executor.ts +41 -34
  24. package/src/runner/executors/shell-executor.ts +96 -52
  25. package/src/runner/executors/subworkflow-executor.ts +16 -0
  26. package/src/runner/executors/types.ts +3 -1
  27. package/src/runner/executors/verification_fixes.test.ts +46 -0
  28. package/src/runner/join-scheduling.test.ts +2 -1
  29. package/src/runner/llm-adapter.integration.test.ts +10 -5
  30. package/src/runner/llm-adapter.ts +57 -18
  31. package/src/runner/llm-clarification.test.ts +4 -1
  32. package/src/runner/llm-executor.test.ts +21 -7
  33. package/src/runner/mcp-client.ts +36 -2
  34. package/src/runner/mcp-server.ts +65 -36
  35. package/src/runner/recovery-security.test.ts +5 -2
  36. package/src/runner/reflexion.test.ts +6 -3
  37. package/src/runner/services/context-builder.ts +13 -4
  38. package/src/runner/services/workflow-validator.ts +2 -1
  39. package/src/runner/standard-tools-ast.test.ts +4 -2
  40. package/src/runner/standard-tools-execution.test.ts +14 -1
  41. package/src/runner/standard-tools-integration.test.ts +6 -0
  42. package/src/runner/standard-tools.ts +13 -10
  43. package/src/runner/step-executor.ts +2 -2
  44. package/src/runner/tool-integration.test.ts +4 -1
  45. package/src/runner/workflow-runner.test.ts +23 -12
  46. package/src/runner/workflow-runner.ts +172 -79
  47. package/src/runner/workflow-state.ts +181 -111
  48. package/src/ui/dashboard.tsx +17 -3
  49. package/src/utils/config-loader.ts +4 -0
  50. package/src/utils/constants.ts +4 -0
  51. package/src/utils/context-injector.test.ts +27 -27
  52. package/src/utils/context-injector.ts +68 -26
  53. package/src/utils/process-sandbox.ts +138 -148
  54. package/src/utils/redactor.ts +39 -9
  55. package/src/utils/resource-loader.ts +24 -19
  56. package/src/utils/sandbox.ts +6 -0
  57. package/src/utils/stream-utils.ts +58 -0
@@ -1,4 +1,5 @@
1
1
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import * as path from 'node:path';
2
3
  import { join } from 'node:path';
3
4
  import { bundleAssets } from './assets.macro.ts' with { type: 'macro' };
4
5
 
@@ -129,30 +130,34 @@ export class ResourceLoader {
129
130
  return false;
130
131
  }
131
132
 
132
- private static getProjectRelativePath(path: string): string | null {
133
+ /**
134
+ * Returns the manifest of embedded assets.
135
+ */
136
+ static getEmbeddedAssets(): Record<string, string> {
137
+ return { ...EMBEDDED_ASSETS };
138
+ }
139
+
140
+ private static getProjectRelativePath(targetPath: string): string | null {
133
141
  const cwd = process.cwd();
134
142
  const keystoneDir = join(cwd, '.keystone');
135
143
 
136
- if (path.startsWith(keystoneDir)) {
137
- return path.slice(keystoneDir.length + 1);
138
- }
139
-
140
- // If it's already relative and starts with .keystone
141
- if (path.startsWith('.keystone/')) {
142
- return path.slice(10);
143
- }
144
-
145
- if (path === '.keystone') {
146
- return '';
144
+ // Use path.resolve to handle potential .. and normalization
145
+ const absTarget = join(cwd, targetPath); // assume relative to cwd if not absolute, checking resolve
146
+ // Actually, join/resolve logic:
147
+ // If targetPath is absolute, resolve returns it. If relative, joins with cwd.
148
+ const resolvedTarget = path.resolve(targetPath);
149
+ const resolvedKeystone = path.resolve(keystoneDir);
150
+
151
+ // Check if target is inside keystone dir
152
+ // We use relative() to check containment
153
+ const rel = path.relative(resolvedKeystone, resolvedTarget);
154
+
155
+ // If rel starts with '..', it is outside. If strictly inside, it won't start with ..
156
+ // Also internal paths shouldn't be absolute (on windows relative might return absolute if different drive)
157
+ if (!rel.startsWith('..') && !path.isAbsolute(rel)) {
158
+ return rel;
147
159
  }
148
160
 
149
161
  return null;
150
162
  }
151
-
152
- /**
153
- * Get all embedded assets for debugging/manifest
154
- */
155
- static getEmbeddedAssets(): Record<string, string> {
156
- return EMBEDDED_ASSETS;
157
- }
158
163
  }
@@ -109,6 +109,12 @@ export class SafeSandbox {
109
109
  options: SandboxOptions = {}
110
110
  ): Promise<unknown> {
111
111
  // Show warning once per process
112
+ if (process.env.NODE_ENV === 'production') {
113
+ throw new Error(
114
+ 'Security Error: Insecure VM fallback is disabled in production environment. Use process isolation.'
115
+ );
116
+ }
117
+
112
118
  if (!SafeSandbox.warned) {
113
119
  SafeSandbox.logger.warn(
114
120
  '\n⚠️ SECURITY WARNING: Using Bun/Node.js built-in VM for script execution.\n' +
@@ -0,0 +1,58 @@
1
+ import { StringDecoder } from 'node:string_decoder';
2
+
3
+ export const TRUNCATED_SUFFIX = '\n... [truncated]';
4
+
5
+ export interface OutputLimiter {
6
+ append(chunk: Buffer | string): void;
7
+ finalize(): string;
8
+ readonly truncated: boolean;
9
+ }
10
+
11
+ /**
12
+ * Creates a limiter that accumulates output up to a maximum number of bytes.
13
+ * Handles multi-byte character boundaries correctly using StringDecoder.
14
+ */
15
+ export function createOutputLimiter(maxBytes: number): OutputLimiter {
16
+ let bytes = 0;
17
+ let text = '';
18
+ let truncated = false;
19
+ // Use StringDecoder to correctly handle multi-byte characters split across chunks
20
+ const decoder = new StringDecoder('utf8');
21
+
22
+ const append = (chunk: Buffer | string) => {
23
+ if (truncated || maxBytes <= 0) {
24
+ truncated = true;
25
+ return;
26
+ }
27
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
28
+ const remaining = maxBytes - bytes;
29
+ if (remaining <= 0) {
30
+ truncated = true;
31
+ return;
32
+ }
33
+ if (buffer.length <= remaining) {
34
+ text += decoder.write(buffer);
35
+ bytes += buffer.length;
36
+ return;
37
+ }
38
+ // Truncate logic: decode up to allowable bytes
39
+ const sub = buffer.subarray(0, remaining);
40
+ text += decoder.write(sub);
41
+ bytes = maxBytes;
42
+ truncated = true;
43
+ };
44
+
45
+ const finalize = () => {
46
+ // Flush any remaining bytes in the decoder
47
+ text += decoder.end();
48
+ return truncated ? `${text}${TRUNCATED_SUFFIX}` : text;
49
+ };
50
+
51
+ return {
52
+ append,
53
+ finalize,
54
+ get truncated() {
55
+ return truncated;
56
+ },
57
+ };
58
+ }