@riotprompt/riotprompt 0.0.20 → 1.0.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 (73) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/MIGRATION.md +235 -0
  3. package/README.md +2 -0
  4. package/SECURITY.md +132 -0
  5. package/dist/builder.js +6 -0
  6. package/dist/builder.js.map +1 -1
  7. package/dist/{cli.cjs → cli.js} +658 -216
  8. package/dist/context-manager.js +1 -1
  9. package/dist/conversation-logger.d.ts +17 -1
  10. package/dist/conversation-logger.js +21 -17
  11. package/dist/conversation-logger.js.map +1 -1
  12. package/dist/conversation.js +1 -1
  13. package/dist/error-handling.d.ts +52 -0
  14. package/dist/error-handling.js +132 -0
  15. package/dist/error-handling.js.map +1 -0
  16. package/dist/formatter.js +1 -1
  17. package/dist/iteration-strategy.js +1 -1
  18. package/dist/loader.js +60 -12
  19. package/dist/loader.js.map +1 -1
  20. package/dist/logger.d.ts +52 -0
  21. package/dist/logger.js +114 -14
  22. package/dist/logger.js.map +1 -1
  23. package/dist/logging-config.d.ts +84 -0
  24. package/dist/logging-config.js +116 -0
  25. package/dist/logging-config.js.map +1 -0
  26. package/dist/message-builder.js +1 -1
  27. package/dist/model-config.js +1 -1
  28. package/dist/override.js +10 -4
  29. package/dist/override.js.map +1 -1
  30. package/dist/recipes.js +6 -0
  31. package/dist/recipes.js.map +1 -1
  32. package/dist/reflection.js +1 -1
  33. package/dist/riotprompt.d.ts +9 -0
  34. package/dist/riotprompt.js +8 -0
  35. package/dist/riotprompt.js.map +1 -1
  36. package/dist/security/audit-logger.d.ts +61 -0
  37. package/dist/security/audit-logger.js +281 -0
  38. package/dist/security/audit-logger.js.map +1 -0
  39. package/dist/security/cli-security.d.ts +143 -0
  40. package/dist/security/cli-security.js +302 -0
  41. package/dist/security/cli-security.js.map +1 -0
  42. package/dist/security/defaults.d.ts +31 -0
  43. package/dist/security/defaults.js +72 -0
  44. package/dist/security/defaults.js.map +1 -0
  45. package/dist/security/events.d.ts +8 -0
  46. package/dist/security/index.d.ts +27 -0
  47. package/dist/security/index.js +22 -0
  48. package/dist/security/index.js.map +1 -0
  49. package/dist/security/path-guard.d.ts +161 -0
  50. package/dist/security/path-guard.js +327 -0
  51. package/dist/security/path-guard.js.map +1 -0
  52. package/dist/security/rate-limiter.d.ts +117 -0
  53. package/dist/security/rate-limiter.js +165 -0
  54. package/dist/security/rate-limiter.js.map +1 -0
  55. package/dist/security/serialization-schemas.d.ts +183 -0
  56. package/dist/security/serialization-schemas.js +174 -0
  57. package/dist/security/serialization-schemas.js.map +1 -0
  58. package/dist/security/timeout-guard.d.ts +123 -0
  59. package/dist/security/timeout-guard.js +223 -0
  60. package/dist/security/timeout-guard.js.map +1 -0
  61. package/dist/security/types.d.ts +86 -0
  62. package/dist/security/types.js +80 -0
  63. package/dist/security/types.js.map +1 -0
  64. package/dist/token-budget.js +1 -1
  65. package/dist/tools.js +1 -1
  66. package/dist/util/storage.js.map +1 -1
  67. package/guide/index.md +2 -0
  68. package/guide/integration.md +1109 -0
  69. package/guide/security.md +237 -0
  70. package/package.json +23 -17
  71. package/vite.config.cli.ts +9 -18
  72. package/dist/riotprompt.cjs +0 -6169
  73. package/dist/riotprompt.cjs.map +0 -1
@@ -1,46 +1,29 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
- require("dotenv/config");
5
- const commander = require("commander");
6
- const cardigantime = require("@theunwalked/cardigantime");
7
- const zod = require("zod");
8
- const fs$1 = require("fs/promises");
9
- const path = require("path");
10
- require("zod-to-json-schema");
11
- const crypto = require("crypto");
12
- require("tiktoken");
13
- const fastXmlParser = require("fast-xml-parser");
14
- const OpenAI = require("openai");
15
- const Anthropic = require("@anthropic-ai/sdk");
16
- const generativeAi = require("@google/generative-ai");
17
- const fs = require("fs");
18
- const glob = require("glob");
19
- function _interopNamespaceDefault(e) {
20
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
21
- if (e) {
22
- for (const k in e) {
23
- if (k !== "default") {
24
- const d = Object.getOwnPropertyDescriptor(e, k);
25
- Object.defineProperty(n, k, d.get ? d : {
26
- enumerable: true,
27
- get: () => e[k]
28
- });
29
- }
30
- }
31
- }
32
- n.default = e;
33
- return Object.freeze(n);
34
- }
35
- const fs__namespace$1 = /* @__PURE__ */ _interopNamespaceDefault(fs$1);
36
- const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
37
- const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
38
- const ConfigSchema = zod.z.object({
39
- defaultModel: zod.z.string().default("gpt-4").describe("Default model to use for formatting"),
40
- promptsDir: zod.z.string().default(".").describe("Directory containing prompts"),
41
- outputDir: zod.z.string().optional().describe("Directory to output formatted prompts")
2
+ import "dotenv/config";
3
+ import { Command } from "commander";
4
+ import { create as create$7 } from "@theunwalked/cardigantime";
5
+ import { z } from "zod";
6
+ import Logging from "@fjell/logging";
7
+ import * as path from "path";
8
+ import path__default from "path";
9
+ import { SafeRegex } from "@theunwalked/pressurelid";
10
+ import "zod-to-json-schema";
11
+ import "tiktoken";
12
+ import { XMLParser } from "fast-xml-parser";
13
+ import OpenAI from "openai";
14
+ import Anthropic from "@anthropic-ai/sdk";
15
+ import { GoogleGenerativeAI } from "@google/generative-ai";
16
+ import { createSafeError as createSafeError$1 } from "@theunwalked/spotclean";
17
+ import { glob } from "glob";
18
+ import * as fs from "fs";
19
+ import crypto from "crypto";
20
+ import * as fs$1 from "fs/promises";
21
+ const ConfigSchema = z.object({
22
+ defaultModel: z.string().default("gpt-4").describe("Default model to use for formatting"),
23
+ promptsDir: z.string().default(".").describe("Directory containing prompts"),
24
+ outputDir: z.string().optional().describe("Directory to output formatted prompts")
42
25
  });
43
- const ParametersSchema = zod.z.record(zod.z.string(), zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.array(zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean()]))]));
26
+ const ParametersSchema = z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.array(z.union([z.string(), z.number(), z.boolean()]))]));
44
27
  const apply = (text, parameters) => {
45
28
  if (!parameters) {
46
29
  return text;
@@ -67,12 +50,12 @@ const apply = (text, parameters) => {
67
50
  }
68
51
  });
69
52
  };
70
- zod.z.object({
71
- text: zod.z.string(),
72
- weight: zod.z.number().optional()
53
+ z.object({
54
+ text: z.string(),
55
+ weight: z.number().optional()
73
56
  });
74
- const WeightedOptionsSchema = zod.z.object({
75
- weight: zod.z.number().optional(),
57
+ const WeightedOptionsSchema = z.object({
58
+ weight: z.number().optional(),
76
59
  parameters: ParametersSchema.optional()
77
60
  });
78
61
  const create$6 = (text, options = {}) => {
@@ -87,10 +70,10 @@ const create$5 = (text, options = {}) => {
87
70
  const weightedOptions = WeightedOptionsSchema.parse(options);
88
71
  return create$6(text, weightedOptions);
89
72
  };
90
- const SectionOptionsSchema = zod.z.object({
91
- title: zod.z.string().optional(),
92
- weight: zod.z.number().optional(),
93
- itemWeight: zod.z.number().optional(),
73
+ const SectionOptionsSchema = z.object({
74
+ title: z.string().optional(),
75
+ weight: z.number().optional(),
76
+ itemWeight: z.number().optional(),
94
77
  parameters: ParametersSchema.optional().default({})
95
78
  });
96
79
  const create$4 = (options = {}) => {
@@ -245,19 +228,60 @@ const DEFAULT_FORMAT_OPTIONS = {
245
228
  sectionTitleProperty: DEFAULT_SECTION_TITLE_PROPERTY,
246
229
  sectionDepth: 0
247
230
  };
248
- const DEFAULT_LOGGER = {
249
- name: "default",
250
- debug: (message, ...args) => console.debug(message, ...args),
251
- info: (message, ...args) => console.info(message, ...args),
252
- warn: (message, ...args) => console.warn(message, ...args),
253
- error: (message, ...args) => console.error(message, ...args),
254
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
255
- verbose: (message, ...args) => {
256
- },
257
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
258
- silly: (message, ...args) => {
231
+ const LibLogger = Logging.getLogger("@theunwalked/riotprompt");
232
+ function createSilentLogger(name) {
233
+ return {
234
+ name,
235
+ debug: () => {
236
+ },
237
+ info: () => {
238
+ },
239
+ warn: () => {
240
+ },
241
+ error: () => {
242
+ },
243
+ verbose: () => {
244
+ },
245
+ silly: () => {
246
+ },
247
+ get: (...components) => createSilentLogger(`${name}:${components.join(":")}`)
248
+ };
249
+ }
250
+ const SILENT_LOGGER = createSilentLogger("silent");
251
+ const isLoggingEnabled = () => {
252
+ return process.env.RIOTPROMPT_LOGGING === "true" || process.env.DEBUG?.includes("riotprompt") || process.env.NODE_ENV === "development";
253
+ };
254
+ function createLoggerFromFjell(fjellLogger, name) {
255
+ return {
256
+ name,
257
+ debug: (message, ...args) => fjellLogger.debug(message, ...args),
258
+ info: (message, ...args) => fjellLogger.info(message, ...args),
259
+ warn: (message, ...args) => fjellLogger.warning(message, ...args),
260
+ error: (message, ...args) => fjellLogger.error(message, ...args),
261
+ verbose: (message, ...args) => fjellLogger.debug(message, ...args),
262
+ // Map to debug
263
+ silly: (message, ...args) => fjellLogger.debug(message, ...args),
264
+ // Map to debug
265
+ get: (...components) => {
266
+ const childLogger = fjellLogger.get(...components);
267
+ return createLoggerFromFjell(childLogger, `${name}:${components.join(":")}`);
268
+ }
269
+ };
270
+ }
271
+ const FJELL_LOGGER = {
272
+ name: "fjell",
273
+ debug: (message, ...args) => LibLogger.debug(message, ...args),
274
+ info: (message, ...args) => LibLogger.info(message, ...args),
275
+ warn: (message, ...args) => LibLogger.warning(message, ...args),
276
+ error: (message, ...args) => LibLogger.error(message, ...args),
277
+ verbose: (message, ...args) => LibLogger.debug(message, ...args),
278
+ silly: (message, ...args) => LibLogger.debug(message, ...args),
279
+ get: (...components) => {
280
+ const childLogger = LibLogger.get(...components);
281
+ return createLoggerFromFjell(childLogger, components.join(":"));
259
282
  }
260
283
  };
284
+ const DEFAULT_LOGGER = isLoggingEnabled() ? FJELL_LOGGER : SILENT_LOGGER;
261
285
  const wrapLogger = (toWrap, name) => {
262
286
  const requiredMethods = ["debug", "info", "warn", "error", "verbose", "silly"];
263
287
  const missingMethods = requiredMethods.filter((method) => typeof toWrap[method] !== "function");
@@ -274,13 +298,14 @@ const wrapLogger = (toWrap, name) => {
274
298
  else if (level === "silly") toWrap.silly(message, ...args);
275
299
  };
276
300
  return {
277
- name: "wrapped",
301
+ name: name || "wrapped",
278
302
  debug: (message, ...args) => log("debug", message, ...args),
279
303
  info: (message, ...args) => log("info", message, ...args),
280
304
  warn: (message, ...args) => log("warn", message, ...args),
281
305
  error: (message, ...args) => log("error", message, ...args),
282
306
  verbose: (message, ...args) => log("verbose", message, ...args),
283
- silly: (message, ...args) => log("silly", message, ...args)
307
+ silly: (message, ...args) => log("silly", message, ...args),
308
+ get: (...components) => wrapLogger(toWrap, name ? `${name}:${components.join(":")}` : components.join(":"))
284
309
  };
285
310
  };
286
311
  class ModelRegistry {
@@ -486,18 +511,18 @@ const stringifyJSON = function(obj, visited = /* @__PURE__ */ new Set()) {
486
511
  }
487
512
  return "";
488
513
  };
489
- const SectionSeparatorSchema = zod.z.enum(["tag", "markdown"]);
490
- const SectionTitlePropertySchema = zod.z.enum(["title", "name"]);
491
- const FormatOptionsSchema = zod.z.object({
514
+ const SectionSeparatorSchema = z.enum(["tag", "markdown"]);
515
+ const SectionTitlePropertySchema = z.enum(["title", "name"]);
516
+ const FormatOptionsSchema = z.object({
492
517
  sectionSeparator: SectionSeparatorSchema,
493
- sectionIndentation: zod.z.boolean(),
518
+ sectionIndentation: z.boolean(),
494
519
  sectionTitleProperty: SectionTitlePropertySchema,
495
- sectionTitlePrefix: zod.z.string().optional(),
496
- sectionTitleSeparator: zod.z.string().optional(),
497
- sectionDepth: zod.z.number().default(0)
520
+ sectionTitlePrefix: z.string().optional(),
521
+ sectionTitleSeparator: z.string().optional(),
522
+ sectionDepth: z.number().default(0)
498
523
  });
499
- const OptionSchema = zod.z.object({
500
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
524
+ const OptionSchema = z.object({
525
+ logger: z.any().optional().default(DEFAULT_LOGGER),
501
526
  formatOptions: FormatOptionsSchema.partial().optional().default(DEFAULT_FORMAT_OPTIONS)
502
527
  });
503
528
  function isSection(obj) {
@@ -622,22 +647,22 @@ ${formattedItems}`;
622
647
  formatArray
623
648
  };
624
649
  };
625
- zod.z.object({
626
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
650
+ z.object({
651
+ logger: z.any().optional().default(DEFAULT_LOGGER),
627
652
  parameters: ParametersSchema.optional().default({})
628
653
  });
629
654
  const create$1 = (params) => {
630
655
  const log = params.log || console.log;
631
656
  const exists = async (path2) => {
632
657
  try {
633
- await fs__namespace.promises.stat(path2);
658
+ await fs.promises.stat(path2);
634
659
  return true;
635
660
  } catch (error) {
636
661
  return false;
637
662
  }
638
663
  };
639
664
  const isDirectory2 = async (path2) => {
640
- const stats = await fs__namespace.promises.stat(path2);
665
+ const stats = await fs.promises.stat(path2);
641
666
  if (!stats.isDirectory()) {
642
667
  log(`${path2} is not a directory`);
643
668
  return false;
@@ -645,7 +670,7 @@ const create$1 = (params) => {
645
670
  return true;
646
671
  };
647
672
  const isFile = async (path2) => {
648
- const stats = await fs__namespace.promises.stat(path2);
673
+ const stats = await fs.promises.stat(path2);
649
674
  if (!stats.isFile()) {
650
675
  log(`${path2} is not a file`);
651
676
  return false;
@@ -654,7 +679,7 @@ const create$1 = (params) => {
654
679
  };
655
680
  const isReadable = async (path2) => {
656
681
  try {
657
- await fs__namespace.promises.access(path2, fs__namespace.constants.R_OK);
682
+ await fs.promises.access(path2, fs.constants.R_OK);
658
683
  } catch (error) {
659
684
  log(`${path2} is not readable: %s %s`, error.message, error.stack);
660
685
  return false;
@@ -663,7 +688,7 @@ const create$1 = (params) => {
663
688
  };
664
689
  const isWritable = async (path2) => {
665
690
  try {
666
- await fs__namespace.promises.access(path2, fs__namespace.constants.W_OK);
691
+ await fs.promises.access(path2, fs.constants.W_OK);
667
692
  } catch (error) {
668
693
  log(`${path2} is not writable: %s %s`, error.message, error.stack);
669
694
  return false;
@@ -681,23 +706,23 @@ const create$1 = (params) => {
681
706
  };
682
707
  const createDirectory = async (path2) => {
683
708
  try {
684
- await fs__namespace.promises.mkdir(path2, { recursive: true });
709
+ await fs.promises.mkdir(path2, { recursive: true });
685
710
  } catch (mkdirError) {
686
711
  throw new Error(`Failed to create output directory ${path2}: ${mkdirError.message} ${mkdirError.stack}`);
687
712
  }
688
713
  };
689
714
  const readFile = async (path2, encoding) => {
690
- return await fs__namespace.promises.readFile(path2, { encoding });
715
+ return await fs.promises.readFile(path2, { encoding });
691
716
  };
692
717
  const writeFile = async (path2, data, encoding) => {
693
- await fs__namespace.promises.writeFile(path2, data, { encoding });
718
+ await fs.promises.writeFile(path2, data, { encoding });
694
719
  };
695
720
  const forEachFileIn = async (directory, callback, options = { pattern: "*.*" }) => {
696
721
  try {
697
722
  let filesProcessed = 0;
698
- const files = await glob.glob(options.pattern, { cwd: directory, nodir: true });
723
+ const files = await glob(options.pattern, { cwd: directory, nodir: true });
699
724
  for (const file of files) {
700
- await callback(path.join(directory, file));
725
+ await callback(path__default.join(directory, file));
701
726
  filesProcessed++;
702
727
  if (options.limit && filesProcessed >= options.limit) {
703
728
  log(`Reached limit of ${options.limit} files, stopping`);
@@ -709,14 +734,14 @@ const create$1 = (params) => {
709
734
  }
710
735
  };
711
736
  const readStream = async (path2) => {
712
- return fs__namespace.createReadStream(path2);
737
+ return fs.createReadStream(path2);
713
738
  };
714
739
  const hashFile = async (path2, length) => {
715
740
  const file = await readFile(path2, "utf8");
716
741
  return crypto.createHash("sha256").update(file).digest("hex").slice(0, length);
717
742
  };
718
743
  const listFiles = async (directory) => {
719
- return await fs__namespace.promises.readdir(directory);
744
+ return await fs.promises.readdir(directory);
720
745
  };
721
746
  return {
722
747
  exists,
@@ -736,11 +761,268 @@ const create$1 = (params) => {
736
761
  listFiles
737
762
  };
738
763
  };
739
- const OptionsSchema = zod.z.object({
740
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
741
- ignorePatterns: zod.z.array(zod.z.string()).optional().default(DEFAULT_IGNORE_PATTERNS),
764
+ const DEFAULT_CONFIG = {
765
+ enabled: true,
766
+ logLevel: "warning",
767
+ includeContext: true,
768
+ maxContextSize: 1e3
769
+ };
770
+ class SecurityAuditLogger {
771
+ config;
772
+ logger;
773
+ eventCount = /* @__PURE__ */ new Map();
774
+ constructor(config = {}, logger) {
775
+ this.config = { ...DEFAULT_CONFIG, ...config };
776
+ this.logger = wrapLogger(logger || DEFAULT_LOGGER, "SecurityAudit");
777
+ }
778
+ /**
779
+ * Log a security event
780
+ */
781
+ log(event) {
782
+ if (!this.config.enabled) return;
783
+ const fullEvent = {
784
+ ...event,
785
+ timestamp: /* @__PURE__ */ new Date(),
786
+ context: this.sanitizeContext(event.context)
787
+ };
788
+ const count = this.eventCount.get(event.type) || 0;
789
+ this.eventCount.set(event.type, count + 1);
790
+ this.config.onEvent?.(fullEvent);
791
+ if (!this.shouldLog(event.severity)) return;
792
+ const logMessage = this.formatEvent(fullEvent);
793
+ switch (event.severity) {
794
+ case "critical":
795
+ this.logger.error(`[CRITICAL] ${logMessage}`);
796
+ break;
797
+ case "error":
798
+ this.logger.error(logMessage);
799
+ break;
800
+ case "warning":
801
+ this.logger.warn(logMessage);
802
+ break;
803
+ case "info":
804
+ this.logger.info(logMessage);
805
+ break;
806
+ }
807
+ }
808
+ /**
809
+ * Convenience methods for common events
810
+ */
811
+ pathTraversalBlocked(path2, reason) {
812
+ this.log({
813
+ type: "path_traversal_blocked",
814
+ severity: "warning",
815
+ message: `Path traversal attempt blocked: ${reason}`,
816
+ context: { attemptedPath: this.sanitizePath(path2) }
817
+ });
818
+ }
819
+ pathValidationFailed(path2, reason) {
820
+ this.log({
821
+ type: "path_validation_failed",
822
+ severity: "warning",
823
+ message: `Path validation failed: ${reason}`,
824
+ context: { attemptedPath: this.sanitizePath(path2) }
825
+ });
826
+ }
827
+ toolValidationFailed(toolName, reason) {
828
+ this.log({
829
+ type: "tool_validation_failed",
830
+ severity: "warning",
831
+ message: `Tool parameter validation failed for "${toolName}": ${reason}`,
832
+ context: { toolName }
833
+ });
834
+ }
835
+ toolExecutionBlocked(toolName, reason) {
836
+ this.log({
837
+ type: "tool_execution_blocked",
838
+ severity: "error",
839
+ message: `Tool execution blocked for "${toolName}": ${reason}`,
840
+ context: { toolName }
841
+ });
842
+ }
843
+ toolTimeout(toolName, timeoutMs) {
844
+ this.log({
845
+ type: "tool_timeout",
846
+ severity: "warning",
847
+ message: `Tool "${toolName}" timed out after ${timeoutMs}ms`,
848
+ context: { toolName, timeoutMs }
849
+ });
850
+ }
851
+ secretRedacted(source) {
852
+ this.log({
853
+ type: "secret_redacted",
854
+ severity: "info",
855
+ message: `Sensitive data redacted from ${source}`,
856
+ context: { source }
857
+ });
858
+ }
859
+ apiKeyUsed(provider) {
860
+ this.log({
861
+ type: "api_key_used",
862
+ severity: "info",
863
+ message: `API key accessed for provider: ${provider}`,
864
+ context: { provider }
865
+ });
866
+ }
867
+ deserializationFailed(source, reason) {
868
+ this.log({
869
+ type: "deserialization_failed",
870
+ severity: "warning",
871
+ message: `Deserialization failed from ${source}: ${reason}`,
872
+ context: { source }
873
+ });
874
+ }
875
+ regexTimeout(pattern, timeoutMs) {
876
+ this.log({
877
+ type: "regex_timeout",
878
+ severity: "warning",
879
+ message: `Regex operation timed out after ${timeoutMs}ms`,
880
+ context: { patternLength: pattern.length, timeoutMs }
881
+ });
882
+ }
883
+ requestTimeout(operation, timeoutMs) {
884
+ this.log({
885
+ type: "request_timeout",
886
+ severity: "warning",
887
+ message: `Operation "${operation}" timed out after ${timeoutMs}ms`,
888
+ context: { operation, timeoutMs }
889
+ });
890
+ }
891
+ rateLimitExceeded(resource, limit) {
892
+ this.log({
893
+ type: "rate_limit_exceeded",
894
+ severity: "warning",
895
+ message: `Rate limit exceeded for ${resource}: limit is ${limit}`,
896
+ context: { resource, limit }
897
+ });
898
+ }
899
+ /**
900
+ * Get event statistics
901
+ */
902
+ getStats() {
903
+ return new Map(this.eventCount);
904
+ }
905
+ /**
906
+ * Get total event count
907
+ */
908
+ getTotalEventCount() {
909
+ let total = 0;
910
+ for (const count of this.eventCount.values()) {
911
+ total += count;
912
+ }
913
+ return total;
914
+ }
915
+ /**
916
+ * Reset statistics
917
+ */
918
+ resetStats() {
919
+ this.eventCount.clear();
920
+ }
921
+ /**
922
+ * Check if any events of a specific type have been logged
923
+ */
924
+ hasEventsOfType(type) {
925
+ return (this.eventCount.get(type) || 0) > 0;
926
+ }
927
+ /**
928
+ * Get count for a specific event type
929
+ */
930
+ getEventCount(type) {
931
+ return this.eventCount.get(type) || 0;
932
+ }
933
+ shouldLog(severity) {
934
+ const levels = ["info", "warning", "error", "critical"];
935
+ const configLevel = levels.indexOf(this.config.logLevel === "all" ? "info" : this.config.logLevel);
936
+ const eventLevel = levels.indexOf(severity);
937
+ return eventLevel >= configLevel;
938
+ }
939
+ formatEvent(event) {
940
+ let message = `[${event.type}] ${event.message}`;
941
+ if (this.config.includeContext && event.context) {
942
+ message += ` | Context: ${JSON.stringify(event.context)}`;
943
+ }
944
+ return message;
945
+ }
946
+ sanitizeContext(context) {
947
+ if (!context || !this.config.includeContext) return void 0;
948
+ const sanitized = {};
949
+ let size = 0;
950
+ for (const [key, value] of Object.entries(context)) {
951
+ const stringValue = String(value);
952
+ if (size + stringValue.length > this.config.maxContextSize) break;
953
+ if (this.looksLikeSensitiveKey(key)) {
954
+ sanitized[key] = "[REDACTED]";
955
+ } else {
956
+ sanitized[key] = value;
957
+ }
958
+ size += stringValue.length;
959
+ }
960
+ return sanitized;
961
+ }
962
+ sanitizePath(path2) {
963
+ const parts = path2.split(/[/\\]/);
964
+ const lastPart = parts[parts.length - 1];
965
+ return `.../${lastPart} (${path2.length} chars)`;
966
+ }
967
+ looksLikeSensitiveKey(key) {
968
+ const sensitivePatterns = [
969
+ /key/i,
970
+ /secret/i,
971
+ /password/i,
972
+ /token/i,
973
+ /auth/i,
974
+ /credential/i
975
+ ];
976
+ return sensitivePatterns.some((p) => p.test(key));
977
+ }
978
+ }
979
+ let globalAuditLogger = null;
980
+ function getAuditLogger() {
981
+ if (!globalAuditLogger) {
982
+ globalAuditLogger = new SecurityAuditLogger();
983
+ }
984
+ return globalAuditLogger;
985
+ }
986
+ function createSafeError(error, context) {
987
+ const err = error instanceof Error ? error : new Error(String(error));
988
+ return createSafeError$1(err, context);
989
+ }
990
+ const OptionsSchema = z.object({
991
+ logger: z.any().optional().default(DEFAULT_LOGGER),
992
+ ignorePatterns: z.array(z.string()).optional().default(DEFAULT_IGNORE_PATTERNS),
742
993
  parameters: ParametersSchema.optional().default({})
743
994
  });
995
+ function createSafeIgnorePatterns(patterns, logger) {
996
+ const auditLogger = getAuditLogger();
997
+ const safeRegex = new SafeRegex({
998
+ maxLength: 500,
999
+ timeoutMs: 1e3,
1000
+ onBlock: (message, pattern) => {
1001
+ logger.warn(`Blocked unsafe ignore pattern: ${message}`, { patternLength: pattern.length });
1002
+ auditLogger.log({
1003
+ type: "regex_blocked",
1004
+ severity: "warning",
1005
+ message: `Blocked unsafe regex pattern: ${message}`,
1006
+ context: { patternLength: pattern.length }
1007
+ });
1008
+ },
1009
+ onWarning: (message, _pattern) => {
1010
+ logger.debug(`Regex warning: ${message}`);
1011
+ }
1012
+ });
1013
+ return patterns.map((pattern) => {
1014
+ const result = safeRegex.create(pattern, "i");
1015
+ if (result.safe && result.regex) {
1016
+ return result.regex;
1017
+ }
1018
+ const globResult = safeRegex.globToRegex(pattern);
1019
+ if (globResult.safe && globResult.regex) {
1020
+ return globResult.regex;
1021
+ }
1022
+ logger.warn(`Invalid or unsafe ignore pattern "${pattern}": ${result.error || globResult.error}`);
1023
+ return null;
1024
+ }).filter((regex) => regex !== null);
1025
+ }
744
1026
  function extractFirstHeader(markdownText) {
745
1027
  const headerRegex = /^(#{1,6})\s+(.+?)(?:\n|$)/m;
746
1028
  const match = markdownText.match(headerRegex);
@@ -783,10 +1065,10 @@ const create = (loaderOptions) => {
783
1065
  const storage = create$1({ log: logger.debug });
784
1066
  for (const contextDir of contextDirectories) {
785
1067
  try {
786
- const dirName = path.basename(contextDir);
1068
+ const dirName = path__default.basename(contextDir);
787
1069
  logger.debug(`Processing context directory ${dirName}`);
788
1070
  let mainContextSection;
789
- const contextFile = path.join(contextDir, "context.md");
1071
+ const contextFile = path__default.join(contextDir, "context.md");
790
1072
  if (await storage.exists(contextFile)) {
791
1073
  logger.debug(`Found context.md file in ${contextDir}`);
792
1074
  const mainContextContent = await storage.readFile(contextFile, "utf8");
@@ -802,22 +1084,15 @@ const create = (loaderOptions) => {
802
1084
  mainContextSection = create$4({ ...sectionOptions, title: dirName });
803
1085
  }
804
1086
  const files = await storage.listFiles(contextDir);
805
- const ignorePatternsRegex = ignorePatterns.map((pattern) => {
806
- try {
807
- return new RegExp(pattern, "i");
808
- } catch (error) {
809
- logger.error(`Invalid ignore pattern: ${pattern}`, { error });
810
- return /(?!)/;
811
- }
812
- });
1087
+ const ignorePatternsRegex = createSafeIgnorePatterns(ignorePatterns, logger);
813
1088
  const filteredFiles = files.filter((file) => {
814
- const fullPath = path.join(contextDir, file);
1089
+ const fullPath = path__default.join(contextDir, file);
815
1090
  return !ignorePatternsRegex.some((regex) => regex.test(file) || regex.test(fullPath));
816
1091
  });
817
1092
  for (const file of filteredFiles) {
818
1093
  if (file === "context.md") continue;
819
1094
  logger.debug(`Processing file ${file} in ${contextDir}`);
820
- const filePath = path.join(contextDir, file);
1095
+ const filePath = path__default.join(contextDir, file);
821
1096
  if (await storage.isFile(filePath)) {
822
1097
  const fileContent = await storage.readFile(filePath, "utf8");
823
1098
  let sectionName = file;
@@ -836,7 +1111,8 @@ const create = (loaderOptions) => {
836
1111
  }
837
1112
  contextSections.push(mainContextSection);
838
1113
  } catch (error) {
839
- logger.error(`Error processing context directory ${contextDir}: ${error}`);
1114
+ const safeError = createSafeError(error, { operation: "load", directory: path__default.basename(contextDir) });
1115
+ logger.error(`Error processing context directory: ${safeError.message}`);
840
1116
  }
841
1117
  }
842
1118
  return contextSections;
@@ -845,107 +1121,108 @@ const create = (loaderOptions) => {
845
1121
  load
846
1122
  };
847
1123
  };
848
- zod.z.object({
849
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
850
- configDirs: zod.z.array(zod.z.string()).default(["./overrides"]),
851
- overrides: zod.z.boolean().default(false),
1124
+ z.object({
1125
+ logger: z.any().optional().default(DEFAULT_LOGGER),
1126
+ configDirs: z.array(z.string()).default(["./overrides"]),
1127
+ overrides: z.boolean().default(false),
852
1128
  parameters: ParametersSchema.optional().default({})
853
1129
  });
854
- zod.z.object({
855
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
856
- basePath: zod.z.string(),
857
- overridePaths: zod.z.array(zod.z.string()).optional().default(["./"]),
858
- overrides: zod.z.boolean().optional().default(false),
1130
+ z.object({
1131
+ logger: z.any().optional().default(DEFAULT_LOGGER),
1132
+ basePath: z.string(),
1133
+ overridePaths: z.array(z.string()).optional().default(["./"]),
1134
+ overrides: z.boolean().optional().default(false),
859
1135
  parameters: ParametersSchema.optional().default({})
860
1136
  });
861
- zod.z.object({
862
- model: zod.z.string(),
863
- formatter: zod.z.any().optional(),
864
- trackContext: zod.z.boolean().optional().default(true),
865
- deduplicateContext: zod.z.boolean().optional().default(true)
1137
+ Logging.getLogger("@theunwalked/riotprompt");
1138
+ z.object({
1139
+ model: z.string(),
1140
+ formatter: z.any().optional(),
1141
+ trackContext: z.boolean().optional().default(true),
1142
+ deduplicateContext: z.boolean().optional().default(true)
866
1143
  });
867
- zod.z.object({
868
- name: zod.z.string().min(1),
869
- description: zod.z.string().min(1),
870
- parameters: zod.z.object({
871
- type: zod.z.literal("object"),
872
- properties: zod.z.record(zod.z.string(), zod.z.any()).default({}),
1144
+ z.object({
1145
+ name: z.string().min(1),
1146
+ description: z.string().min(1),
1147
+ parameters: z.object({
1148
+ type: z.literal("object"),
1149
+ properties: z.record(z.string(), z.any()).default({}),
873
1150
  // Allow any parameter structure
874
- required: zod.z.array(zod.z.string()).optional()
1151
+ required: z.array(z.string()).optional()
875
1152
  }).passthrough(),
876
1153
  // Allow additional fields
877
- execute: zod.z.custom(
1154
+ execute: z.custom(
878
1155
  (val) => typeof val === "function",
879
1156
  { message: "execute must be a function" }
880
1157
  ),
881
- category: zod.z.string().optional(),
882
- cost: zod.z.enum(["cheap", "moderate", "expensive"]).optional(),
883
- examples: zod.z.array(zod.z.object({
884
- scenario: zod.z.string(),
885
- params: zod.z.any(),
886
- expectedResult: zod.z.string()
1158
+ category: z.string().optional(),
1159
+ cost: z.enum(["cheap", "moderate", "expensive"]).optional(),
1160
+ examples: z.array(z.object({
1161
+ scenario: z.string(),
1162
+ params: z.any(),
1163
+ expectedResult: z.string()
887
1164
  })).optional()
888
1165
  }).passthrough();
889
- const ContentItemSchema = zod.z.union([
890
- zod.z.string(),
1166
+ const ContentItemSchema = z.union([
1167
+ z.string(),
891
1168
  // Simple string content
892
- zod.z.object({
893
- content: zod.z.string(),
894
- title: zod.z.string().optional(),
895
- weight: zod.z.number().optional()
1169
+ z.object({
1170
+ content: z.string(),
1171
+ title: z.string().optional(),
1172
+ weight: z.number().optional()
896
1173
  }),
897
- zod.z.object({
898
- path: zod.z.string(),
899
- title: zod.z.string().optional(),
900
- weight: zod.z.number().optional()
1174
+ z.object({
1175
+ path: z.string(),
1176
+ title: z.string().optional(),
1177
+ weight: z.number().optional()
901
1178
  }),
902
- zod.z.object({
903
- directories: zod.z.array(zod.z.string()),
904
- title: zod.z.string().optional(),
905
- weight: zod.z.number().optional()
1179
+ z.object({
1180
+ directories: z.array(z.string()),
1181
+ title: z.string().optional(),
1182
+ weight: z.number().optional()
906
1183
  })
907
1184
  ]);
908
- zod.z.object({
1185
+ z.object({
909
1186
  // Core settings
910
- basePath: zod.z.string(),
911
- logger: zod.z.any().optional().default(DEFAULT_LOGGER),
912
- overridePaths: zod.z.array(zod.z.string()).optional().default(["./"]),
913
- overrides: zod.z.boolean().optional().default(false),
1187
+ basePath: z.string(),
1188
+ logger: z.any().optional().default(DEFAULT_LOGGER),
1189
+ overridePaths: z.array(z.string()).optional().default(["./"]),
1190
+ overrides: z.boolean().optional().default(false),
914
1191
  parameters: ParametersSchema.optional().default({}),
915
1192
  // Content sections
916
1193
  persona: ContentItemSchema.optional(),
917
- instructions: zod.z.array(ContentItemSchema).optional().default([]),
918
- content: zod.z.array(ContentItemSchema).optional().default([]),
919
- context: zod.z.array(ContentItemSchema).optional().default([]),
1194
+ instructions: z.array(ContentItemSchema).optional().default([]),
1195
+ content: z.array(ContentItemSchema).optional().default([]),
1196
+ context: z.array(ContentItemSchema).optional().default([]),
920
1197
  // Advanced prompting sections
921
- constraints: zod.z.array(ContentItemSchema).optional().default([]),
922
- tone: zod.z.array(ContentItemSchema).optional().default([]),
923
- examples: zod.z.array(ContentItemSchema).optional().default([]),
924
- reasoning: zod.z.array(ContentItemSchema).optional().default([]),
925
- responseFormat: zod.z.array(ContentItemSchema).optional().default([]),
926
- recap: zod.z.array(ContentItemSchema).optional().default([]),
927
- safeguards: zod.z.array(ContentItemSchema).optional().default([]),
928
- schema: zod.z.any().optional(),
1198
+ constraints: z.array(ContentItemSchema).optional().default([]),
1199
+ tone: z.array(ContentItemSchema).optional().default([]),
1200
+ examples: z.array(ContentItemSchema).optional().default([]),
1201
+ reasoning: z.array(ContentItemSchema).optional().default([]),
1202
+ responseFormat: z.array(ContentItemSchema).optional().default([]),
1203
+ recap: z.array(ContentItemSchema).optional().default([]),
1204
+ safeguards: z.array(ContentItemSchema).optional().default([]),
1205
+ schema: z.any().optional(),
929
1206
  // Can be string path, JSON object, or Zod schema
930
1207
  // Templates and inheritance
931
- extends: zod.z.string().optional(),
1208
+ extends: z.string().optional(),
932
1209
  // Extend another recipe
933
- template: zod.z.string().optional(),
1210
+ template: z.string().optional(),
934
1211
  // Generic template name
935
1212
  // Tool integration
936
- tools: zod.z.any().optional(),
1213
+ tools: z.any().optional(),
937
1214
  // Tool[] | ToolRegistry
938
- toolGuidance: zod.z.union([
939
- zod.z.enum(["auto", "minimal", "detailed"]),
940
- zod.z.object({
941
- strategy: zod.z.enum(["adaptive", "prescriptive", "minimal"]),
942
- includeExamples: zod.z.boolean().optional(),
943
- explainWhenToUse: zod.z.boolean().optional(),
944
- includeCategories: zod.z.boolean().optional(),
945
- customInstructions: zod.z.string().optional()
1215
+ toolGuidance: z.union([
1216
+ z.enum(["auto", "minimal", "detailed"]),
1217
+ z.object({
1218
+ strategy: z.enum(["adaptive", "prescriptive", "minimal"]),
1219
+ includeExamples: z.boolean().optional(),
1220
+ explainWhenToUse: z.boolean().optional(),
1221
+ includeCategories: z.boolean().optional(),
1222
+ customInstructions: z.string().optional()
946
1223
  })
947
1224
  ]).optional(),
948
- toolCategories: zod.z.array(zod.z.string()).optional()
1225
+ toolCategories: z.array(z.string()).optional()
949
1226
  });
950
1227
  const toJSON = (prompt) => {
951
1228
  return JSON.stringify(prompt, null, 2);
@@ -1087,7 +1364,7 @@ const parseNodeToSection = (node) => {
1087
1364
  return section;
1088
1365
  };
1089
1366
  const fromXML = (xmlString) => {
1090
- const parser = new fastXmlParser.XMLParser({
1367
+ const parser = new XMLParser({
1091
1368
  ignoreAttributes: false,
1092
1369
  attributeNamePrefix: "@_",
1093
1370
  preserveOrder: true,
@@ -1129,18 +1406,18 @@ const fromXML = (xmlString) => {
1129
1406
  });
1130
1407
  };
1131
1408
  const saveToDirectory = async (prompt, basePath) => {
1132
- await fs__namespace$1.mkdir(basePath, { recursive: true });
1409
+ await fs$1.mkdir(basePath, { recursive: true });
1133
1410
  if (prompt.persona) {
1134
- await saveSection(prompt.persona, path__namespace.join(basePath, "persona"));
1411
+ await saveSection(prompt.persona, path.join(basePath, "persona"));
1135
1412
  }
1136
1413
  if (prompt.instructions) {
1137
- await saveSection(prompt.instructions, path__namespace.join(basePath, "instructions"));
1414
+ await saveSection(prompt.instructions, path.join(basePath, "instructions"));
1138
1415
  }
1139
1416
  if (prompt.contexts) {
1140
- await saveSection(prompt.contexts, path__namespace.join(basePath, "context"));
1417
+ await saveSection(prompt.contexts, path.join(basePath, "context"));
1141
1418
  }
1142
1419
  if (prompt.contents) {
1143
- await saveSection(prompt.contents, path__namespace.join(basePath, "content"));
1420
+ await saveSection(prompt.contents, path.join(basePath, "content"));
1144
1421
  }
1145
1422
  };
1146
1423
  const saveSection = async (section, targetPath) => {
@@ -1152,20 +1429,20 @@ const saveSection = async (section, targetPath) => {
1152
1429
  if (typeof item === "string") return item;
1153
1430
  return item.text;
1154
1431
  }).join("\n\n");
1155
- await fs__namespace$1.writeFile(`${targetPath}.md`, content);
1432
+ await fs$1.writeFile(`${targetPath}.md`, content);
1156
1433
  return;
1157
1434
  }
1158
- await fs__namespace$1.mkdir(targetPath, { recursive: true });
1435
+ await fs$1.mkdir(targetPath, { recursive: true });
1159
1436
  for (let i = 0; i < section.items.length; i++) {
1160
1437
  const item = section.items[i];
1161
1438
  if (typeof item === "object" && "items" in item) {
1162
1439
  const subTitle = item.title || `part-${i + 1}`;
1163
- const subPath = path__namespace.join(targetPath, subTitle);
1440
+ const subPath = path.join(targetPath, subTitle);
1164
1441
  await saveSection(item, subPath);
1165
1442
  } else {
1166
1443
  const fileName = `item-${i + 1}.md`;
1167
1444
  const content = typeof item === "string" ? item : item.text;
1168
- await fs__namespace$1.writeFile(path__namespace.join(targetPath, fileName), content);
1445
+ await fs$1.writeFile(path.join(targetPath, fileName), content);
1169
1446
  }
1170
1447
  }
1171
1448
  };
@@ -1258,7 +1535,7 @@ class GeminiProvider {
1258
1535
  async execute(request, options = {}) {
1259
1536
  const apiKey = options.apiKey || process.env.GEMINI_API_KEY;
1260
1537
  if (!apiKey) throw new Error("Gemini API key is required");
1261
- const genAI = new generativeAi.GoogleGenerativeAI(apiKey);
1538
+ const genAI = new GoogleGenerativeAI(apiKey);
1262
1539
  const modelName = options.model || request.model || "gemini-1.5-pro";
1263
1540
  const generationConfig = {};
1264
1541
  if (request.responseFormat?.type === "json_schema") {
@@ -1364,8 +1641,170 @@ const execute = async (request, options = {}) => {
1364
1641
  const manager = new ExecutionManager();
1365
1642
  return manager.execute(request, options);
1366
1643
  };
1367
- const program = new commander.Command();
1368
- const configManager = cardigantime.create({
1644
+ const PathSecurityConfigSchema = z.object({
1645
+ enabled: z.boolean().optional().default(true),
1646
+ basePaths: z.array(z.string()).optional().default([]),
1647
+ allowAbsolute: z.boolean().optional().default(false),
1648
+ allowSymlinks: z.boolean().optional().default(false),
1649
+ denyPatterns: z.array(z.string()).optional().default([
1650
+ "\\.\\.",
1651
+ // Parent directory
1652
+ "~",
1653
+ // Home directory expansion
1654
+ "\\$\\{"
1655
+ // Variable expansion
1656
+ ])
1657
+ });
1658
+ const ToolSecurityConfigSchema = z.object({
1659
+ enabled: z.boolean().optional().default(true),
1660
+ validateParams: z.boolean().optional().default(true),
1661
+ sandboxExecution: z.boolean().optional().default(false),
1662
+ allowedTools: z.array(z.string()).optional(),
1663
+ deniedTools: z.array(z.string()).optional().default([]),
1664
+ maxExecutionTime: z.number().optional().default(3e4),
1665
+ // 30 seconds
1666
+ maxConcurrentCalls: z.number().optional().default(10)
1667
+ });
1668
+ const SecretSecurityConfigSchema = z.object({
1669
+ enabled: z.boolean().optional().default(true),
1670
+ redactInLogs: z.boolean().optional().default(true),
1671
+ redactInErrors: z.boolean().optional().default(true),
1672
+ patterns: z.array(z.instanceof(RegExp)).optional().default([
1673
+ /api[_-]?key[\s:="']+[\w-]+/gi,
1674
+ /password[\s:="']+[\w-]+/gi,
1675
+ /Bearer\s+[\w-]+/gi,
1676
+ /sk-[a-zA-Z0-9]{48,}/g,
1677
+ /AKIA[0-9A-Z]{16}/g
1678
+ // AWS Access Key
1679
+ ]),
1680
+ customPatterns: z.array(z.instanceof(RegExp)).optional().default([])
1681
+ });
1682
+ const LogSecurityConfigSchema = z.object({
1683
+ enabled: z.boolean().optional().default(true),
1684
+ auditSecurityEvents: z.boolean().optional().default(true),
1685
+ sanitizeStackTraces: z.boolean().optional().default(true),
1686
+ maxContentLength: z.number().optional().default(1e4)
1687
+ });
1688
+ const TimeoutConfigSchema = z.object({
1689
+ enabled: z.boolean().optional().default(true),
1690
+ defaultTimeout: z.number().optional().default(3e4),
1691
+ llmTimeout: z.number().optional().default(12e4),
1692
+ // 2 minutes for LLM calls
1693
+ toolTimeout: z.number().optional().default(3e4),
1694
+ fileTimeout: z.number().optional().default(5e3)
1695
+ });
1696
+ function createDefaultPathSecurityConfig() {
1697
+ return PathSecurityConfigSchema.parse({});
1698
+ }
1699
+ function createDefaultToolSecurityConfig() {
1700
+ return ToolSecurityConfigSchema.parse({});
1701
+ }
1702
+ function createDefaultSecretSecurityConfig() {
1703
+ return SecretSecurityConfigSchema.parse({});
1704
+ }
1705
+ function createDefaultLogSecurityConfig() {
1706
+ return LogSecurityConfigSchema.parse({});
1707
+ }
1708
+ function createDefaultTimeoutConfig() {
1709
+ return TimeoutConfigSchema.parse({});
1710
+ }
1711
+ const SecurityConfigSchema = z.object({
1712
+ paths: PathSecurityConfigSchema.optional().default(createDefaultPathSecurityConfig),
1713
+ tools: ToolSecurityConfigSchema.optional().default(createDefaultToolSecurityConfig),
1714
+ secrets: SecretSecurityConfigSchema.optional().default(createDefaultSecretSecurityConfig),
1715
+ logging: LogSecurityConfigSchema.optional().default(createDefaultLogSecurityConfig),
1716
+ timeouts: TimeoutConfigSchema.optional().default(createDefaultTimeoutConfig)
1717
+ });
1718
+ SecurityConfigSchema.parse({});
1719
+ const SERIALIZATION_LIMITS = {
1720
+ maxContentLength: 1e6,
1721
+ // 1MB per message
1722
+ maxArgumentsLength: 1e5,
1723
+ // 100KB for tool arguments
1724
+ maxMessages: 1e4,
1725
+ // 10k messages per conversation
1726
+ maxContextItems: 1e3,
1727
+ // 1k context items
1728
+ maxStringLength: 100,
1729
+ // 100 chars for names/ids
1730
+ maxToolCalls: 100
1731
+ // 100 tool calls per message
1732
+ };
1733
+ const ToolCallSchema = z.object({
1734
+ id: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
1735
+ type: z.literal("function"),
1736
+ function: z.object({
1737
+ name: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
1738
+ arguments: z.string().max(SERIALIZATION_LIMITS.maxArgumentsLength)
1739
+ })
1740
+ });
1741
+ const ConversationMessageSchema = z.object({
1742
+ role: z.enum(["system", "user", "assistant", "tool"]),
1743
+ content: z.string().nullable().refine(
1744
+ (val) => val === null || val.length <= SERIALIZATION_LIMITS.maxContentLength,
1745
+ { message: `Content exceeds maximum length of ${SERIALIZATION_LIMITS.maxContentLength}` }
1746
+ ),
1747
+ name: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional(),
1748
+ tool_calls: z.array(ToolCallSchema).max(SERIALIZATION_LIMITS.maxToolCalls).optional(),
1749
+ tool_call_id: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional()
1750
+ });
1751
+ const ConversationMetadataSchema = z.object({
1752
+ model: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
1753
+ created: z.string().datetime(),
1754
+ lastModified: z.string().datetime(),
1755
+ messageCount: z.number().int().nonnegative(),
1756
+ toolCallCount: z.number().int().nonnegative()
1757
+ });
1758
+ z.object({
1759
+ // Optional version for forward compatibility
1760
+ version: z.string().optional(),
1761
+ messages: z.array(ConversationMessageSchema).max(SERIALIZATION_LIMITS.maxMessages),
1762
+ metadata: ConversationMetadataSchema,
1763
+ contextProvided: z.array(z.string().max(1e3)).max(SERIALIZATION_LIMITS.maxContextItems).optional()
1764
+ });
1765
+ z.object({
1766
+ version: z.string().optional(),
1767
+ persona: z.any().optional(),
1768
+ instructions: z.any().optional(),
1769
+ contexts: z.any().optional(),
1770
+ content: z.any().optional()
1771
+ });
1772
+ z.object({
1773
+ id: z.string().max(200),
1774
+ metadata: z.object({
1775
+ startTime: z.union([z.string().datetime(), z.date()]),
1776
+ endTime: z.union([z.string().datetime(), z.date()]).optional(),
1777
+ duration: z.number().nonnegative().optional(),
1778
+ model: z.string().max(SERIALIZATION_LIMITS.maxStringLength),
1779
+ template: z.string().max(SERIALIZATION_LIMITS.maxStringLength).optional(),
1780
+ userContext: z.record(z.string(), z.any()).optional()
1781
+ }),
1782
+ prompt: z.object({
1783
+ persona: z.string().optional(),
1784
+ instructions: z.string().optional(),
1785
+ content: z.array(z.string()).optional(),
1786
+ context: z.array(z.string()).optional()
1787
+ }).optional(),
1788
+ messages: z.array(z.object({
1789
+ index: z.number().int().nonnegative(),
1790
+ timestamp: z.string(),
1791
+ role: z.string(),
1792
+ content: z.string().nullable(),
1793
+ tool_calls: z.array(ToolCallSchema).optional(),
1794
+ tool_call_id: z.string().optional(),
1795
+ metadata: z.record(z.string(), z.any()).optional()
1796
+ })).max(SERIALIZATION_LIMITS.maxMessages),
1797
+ summary: z.object({
1798
+ totalMessages: z.number().int().nonnegative(),
1799
+ totalTokens: z.number().int().nonnegative().optional(),
1800
+ toolCallsExecuted: z.number().int().nonnegative(),
1801
+ iterations: z.number().int().nonnegative(),
1802
+ finalOutput: z.string().optional(),
1803
+ success: z.boolean()
1804
+ })
1805
+ });
1806
+ const program = new Command();
1807
+ const configManager = create$7({
1369
1808
  configShape: ConfigSchema.shape,
1370
1809
  defaults: {
1371
1810
  configDirectory: process.cwd(),
@@ -1375,7 +1814,7 @@ const configManager = cardigantime.create({
1375
1814
  program.name("riotprompt").description("CLI tool for analyzing and processing prompts").version("0.0.1");
1376
1815
  async function isDirectory(path2) {
1377
1816
  try {
1378
- const stat = await fs__namespace$1.stat(path2);
1817
+ const stat = await fs$1.stat(path2);
1379
1818
  return stat.isDirectory();
1380
1819
  } catch {
1381
1820
  return false;
@@ -1383,7 +1822,7 @@ async function isDirectory(path2) {
1383
1822
  }
1384
1823
  async function fileExists(path2) {
1385
1824
  try {
1386
- await fs__namespace$1.access(path2);
1825
+ await fs$1.access(path2);
1387
1826
  return true;
1388
1827
  } catch {
1389
1828
  return false;
@@ -1394,8 +1833,8 @@ async function loadPromptFromDirectory(absolutePromptPath) {
1394
1833
  let instructionsSection;
1395
1834
  let contextSection;
1396
1835
  const loader = create();
1397
- const personaDir = path__namespace.join(absolutePromptPath, "persona");
1398
- const personaFile = path__namespace.join(absolutePromptPath, "persona.md");
1836
+ const personaDir = path.join(absolutePromptPath, "persona");
1837
+ const personaFile = path.join(absolutePromptPath, "persona.md");
1399
1838
  if (await isDirectory(personaDir)) {
1400
1839
  console.log("Loading persona from directory...");
1401
1840
  const personaSections = await loader.load([personaDir]);
@@ -1407,14 +1846,14 @@ async function loadPromptFromDirectory(absolutePromptPath) {
1407
1846
  }
1408
1847
  } else if (await fileExists(personaFile)) {
1409
1848
  console.log("Loading persona from file...");
1410
- const personaContent = await fs__namespace$1.readFile(personaFile, "utf-8");
1849
+ const personaContent = await fs$1.readFile(personaFile, "utf-8");
1411
1850
  personaSection = create$4({ title: "Persona" });
1412
1851
  personaSection.add(create$5(personaContent));
1413
1852
  } else {
1414
1853
  console.log("No persona found, skipping.");
1415
1854
  }
1416
- const instructionsDir = path__namespace.join(absolutePromptPath, "instructions");
1417
- const instructionsFile = path__namespace.join(absolutePromptPath, "instructions.md");
1855
+ const instructionsDir = path.join(absolutePromptPath, "instructions");
1856
+ const instructionsFile = path.join(absolutePromptPath, "instructions.md");
1418
1857
  if (await isDirectory(instructionsDir)) {
1419
1858
  console.log("Loading instructions from directory...");
1420
1859
  const instructionSections = await loader.load([instructionsDir]);
@@ -1426,14 +1865,14 @@ async function loadPromptFromDirectory(absolutePromptPath) {
1426
1865
  }
1427
1866
  } else if (await fileExists(instructionsFile)) {
1428
1867
  console.log("Loading instructions from file...");
1429
- const instructionsContent = await fs__namespace$1.readFile(instructionsFile, "utf-8");
1868
+ const instructionsContent = await fs$1.readFile(instructionsFile, "utf-8");
1430
1869
  instructionsSection = create$4({ title: "Instructions" });
1431
1870
  instructionsSection.add(create$5(instructionsContent));
1432
1871
  }
1433
1872
  if (!instructionsSection) {
1434
1873
  throw new Error("instructions (directory or .md file) is required.");
1435
1874
  }
1436
- const contextDir = path__namespace.join(absolutePromptPath, "context");
1875
+ const contextDir = path.join(absolutePromptPath, "context");
1437
1876
  if (await isDirectory(contextDir)) {
1438
1877
  console.log("Loading context from directory...");
1439
1878
  const contextSections = await loader.load([contextDir]);
@@ -1454,14 +1893,14 @@ async function loadPromptFromDirectory(absolutePromptPath) {
1454
1893
  }
1455
1894
  async function createAction(promptName, options) {
1456
1895
  try {
1457
- const basePath = path__namespace.resolve(options.path, promptName);
1896
+ const basePath = path.resolve(options.path, promptName);
1458
1897
  if (await fileExists(basePath)) {
1459
1898
  console.error(`Error: Directory ${basePath} already exists.`);
1460
1899
  process.exit(1);
1461
1900
  }
1462
1901
  if (options.import) {
1463
1902
  console.log(`Importing prompt from ${options.import} to ${basePath}...`);
1464
- const content = await fs__namespace$1.readFile(options.import, "utf-8");
1903
+ const content = await fs$1.readFile(options.import, "utf-8");
1465
1904
  let prompt;
1466
1905
  if (options.import.endsWith(".json")) {
1467
1906
  prompt = fromJSON(content);
@@ -1474,23 +1913,23 @@ async function createAction(promptName, options) {
1474
1913
  console.log(`Successfully imported to ${basePath}`);
1475
1914
  } else {
1476
1915
  console.log(`Creating prompt structure at ${basePath}...`);
1477
- await fs__namespace$1.mkdir(basePath, { recursive: true });
1916
+ await fs$1.mkdir(basePath, { recursive: true });
1478
1917
  const personaText = options.persona || "You are a helpful AI assistant.";
1479
- await fs__namespace$1.writeFile(path__namespace.join(basePath, "persona.md"), personaText);
1918
+ await fs$1.writeFile(path.join(basePath, "persona.md"), personaText);
1480
1919
  console.log("Created persona.md");
1481
1920
  const instructionsText = options.instructions || "Please analyze the following request.";
1482
- await fs__namespace$1.writeFile(path__namespace.join(basePath, "instructions.md"), instructionsText);
1921
+ await fs$1.writeFile(path.join(basePath, "instructions.md"), instructionsText);
1483
1922
  console.log("Created instructions.md");
1484
1923
  if (options.context) {
1485
- const contextDir = path__namespace.join(basePath, "context");
1486
- await fs__namespace$1.mkdir(contextDir);
1487
- await fs__namespace$1.writeFile(path__namespace.join(contextDir, "README.md"), "Place context files (json, md, txt) in this directory.");
1924
+ const contextDir = path.join(basePath, "context");
1925
+ await fs$1.mkdir(contextDir);
1926
+ await fs$1.writeFile(path.join(contextDir, "README.md"), "Place context files (json, md, txt) in this directory.");
1488
1927
  console.log("Created context directory");
1489
1928
  }
1490
1929
  console.log(`
1491
1930
  Prompt '${promptName}' created successfully!`);
1492
1931
  }
1493
- console.log(`Run 'riotprompt process ${path__namespace.join(options.path, promptName)}' to test it.`);
1932
+ console.log(`Run 'riotprompt process ${path.join(options.path, promptName)}' to test it.`);
1494
1933
  } catch (error) {
1495
1934
  console.error("Error creating prompt:", error);
1496
1935
  process.exit(1);
@@ -1502,7 +1941,7 @@ async function processAction(promptPath, options) {
1502
1941
  const modelName = options.model || config.defaultModel;
1503
1942
  console.log(`Processing prompt from: ${promptPath}`);
1504
1943
  console.log(`Using model: ${modelName}`);
1505
- const absolutePromptPath = path__namespace.resolve(promptPath);
1944
+ const absolutePromptPath = path.resolve(promptPath);
1506
1945
  if (!await fileExists(absolutePromptPath)) {
1507
1946
  console.error(`Error: Prompt path not found at ${absolutePromptPath}`);
1508
1947
  process.exit(1);
@@ -1511,7 +1950,7 @@ async function processAction(promptPath, options) {
1511
1950
  if (await isDirectory(absolutePromptPath)) {
1512
1951
  prompt = await loadPromptFromDirectory(absolutePromptPath);
1513
1952
  } else {
1514
- const content = await fs__namespace$1.readFile(absolutePromptPath, "utf-8");
1953
+ const content = await fs$1.readFile(absolutePromptPath, "utf-8");
1515
1954
  if (absolutePromptPath.endsWith(".json")) {
1516
1955
  prompt = fromJSON(content);
1517
1956
  } else if (absolutePromptPath.endsWith(".xml")) {
@@ -1538,7 +1977,7 @@ ${m.content}`).join("\n\n");
1538
1977
  }
1539
1978
  }
1540
1979
  if (options.output) {
1541
- await fs__namespace$1.writeFile(options.output, output);
1980
+ await fs$1.writeFile(options.output, output);
1542
1981
  console.log(`Output written to ${options.output}`);
1543
1982
  } else {
1544
1983
  console.log("\n--- Result ---\n");
@@ -1555,7 +1994,7 @@ async function executeAction(promptPath, options) {
1555
1994
  const modelName = options.model || config.defaultModel;
1556
1995
  console.log(`Executing prompt from: ${promptPath}`);
1557
1996
  console.log(`Using model: ${modelName}`);
1558
- const absolutePromptPath = path__namespace.resolve(promptPath);
1997
+ const absolutePromptPath = path.resolve(promptPath);
1559
1998
  if (!await fileExists(absolutePromptPath)) {
1560
1999
  console.error(`Error: Prompt path not found at ${absolutePromptPath}`);
1561
2000
  process.exit(1);
@@ -1564,7 +2003,7 @@ async function executeAction(promptPath, options) {
1564
2003
  if (await isDirectory(absolutePromptPath)) {
1565
2004
  prompt = await loadPromptFromDirectory(absolutePromptPath);
1566
2005
  } else {
1567
- const content = await fs__namespace$1.readFile(absolutePromptPath, "utf-8");
2006
+ const content = await fs$1.readFile(absolutePromptPath, "utf-8");
1568
2007
  if (absolutePromptPath.endsWith(".json")) {
1569
2008
  prompt = fromJSON(content);
1570
2009
  } else if (absolutePromptPath.endsWith(".xml")) {
@@ -1602,16 +2041,19 @@ async function main() {
1602
2041
  program.command("execute <promptPath>").description("Execute a prompt using an LLM provider").option("-m, --model <model>", "Model to use (e.g., gpt-4, claude-3-opus, gemini-1.5-pro)").option("-k, --key <key>", "API Key (overrides env vars)").option("-t, --temperature <number>", "Temperature (0-1)", parseFloat).option("--max-tokens <number>", "Max tokens", parseInt).action(executeAction);
1603
2042
  await program.parseAsync();
1604
2043
  }
1605
- if (typeof require !== "undefined" && require.main === module) {
2044
+ const isRunningAsCLI = process.argv[1] && (process.argv[1].endsWith("cli.js") || process.argv[1].endsWith("cli.ts")) && !process.argv[1].includes("vitest") && !process.argv[1].includes("node_modules");
2045
+ if (isRunningAsCLI) {
1606
2046
  main().catch((err) => {
1607
2047
  console.error(err);
1608
2048
  process.exit(1);
1609
2049
  });
1610
2050
  }
1611
- exports.createAction = createAction;
1612
- exports.executeAction = executeAction;
1613
- exports.fileExists = fileExists;
1614
- exports.isDirectory = isDirectory;
1615
- exports.loadPromptFromDirectory = loadPromptFromDirectory;
1616
- exports.main = main;
1617
- exports.processAction = processAction;
2051
+ export {
2052
+ createAction,
2053
+ executeAction,
2054
+ fileExists,
2055
+ isDirectory,
2056
+ loadPromptFromDirectory,
2057
+ main,
2058
+ processAction
2059
+ };