@stackmemoryai/stackmemory
Version:
Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.
198 lines (197 loc) • 6.89 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { z } from "zod";
import { logConfigInvalid } from "./security-logger.js";
const PromptOptionSchema = z.object({
key: z.string().max(10),
label: z.string().max(200),
action: z.string().max(500).optional()
});
const PendingPromptSchema = z.object({
id: z.string().max(32),
timestamp: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/)),
message: z.string().max(1e3),
options: z.array(PromptOptionSchema).max(10),
type: z.enum(["options", "yesno", "freeform"]),
callback: z.string().max(500).optional(),
expiresAt: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/))
});
const NotifyOnSchema = z.object({
taskComplete: z.boolean(),
reviewReady: z.boolean(),
error: z.boolean(),
custom: z.boolean(),
contextSync: z.boolean().optional().default(true)
});
const QuietHoursSchema = z.object({
enabled: z.boolean(),
start: z.string().regex(/^\d{2}:\d{2}$/),
end: z.string().regex(/^\d{2}:\d{2}$/)
});
const SMSConfigSchema = z.object({
enabled: z.boolean(),
channel: z.enum(["whatsapp", "sms"]),
accountSid: z.string().max(100).optional(),
authToken: z.string().max(100).optional(),
smsFromNumber: z.string().max(20).optional(),
smsToNumber: z.string().max(20).optional(),
whatsappFromNumber: z.string().max(30).optional(),
whatsappToNumber: z.string().max(30).optional(),
fromNumber: z.string().max(20).optional(),
toNumber: z.string().max(20).optional(),
webhookUrl: z.string().url().max(500).optional(),
notifyOn: NotifyOnSchema,
quietHours: QuietHoursSchema.optional(),
responseTimeout: z.number().int().min(30).max(3600),
pendingPrompts: z.array(PendingPromptSchema).max(100)
});
const PendingActionSchema = z.object({
id: z.string().max(32),
promptId: z.string().max(32),
response: z.string().max(1e3),
action: z.string().max(500),
timestamp: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/)),
status: z.enum(["pending", "running", "completed", "failed"]),
result: z.string().max(1e4).optional(),
error: z.string().max(1e3).optional()
});
const ActionQueueSchema = z.object({
actions: z.array(PendingActionSchema).max(1e3),
lastChecked: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/))
});
const AutoBackgroundConfigSchema = z.object({
enabled: z.boolean(),
timeoutMs: z.number().int().min(1e3).max(6e5),
alwaysBackground: z.array(z.string().max(200)).max(100),
neverBackground: z.array(z.string().max(200)).max(100),
verbose: z.boolean().optional()
});
const SyncOptionsSchema = z.object({
autoSyncOnClose: z.boolean(),
minFrameDuration: z.number().int().min(0).max(3600),
// 0 to 1 hour
includeDecisions: z.boolean(),
includeFiles: z.boolean(),
includeTests: z.boolean(),
maxDigestLength: z.number().int().min(100).max(1e3)
// WhatsApp limit ~4096 chars
});
const ScheduleConfigSchema = z.object({
type: z.enum(["daily", "hourly", "interval"]),
time: z.string().regex(/^\d{2}:\d{2}$/).optional(),
// "HH:MM" for daily
intervalMinutes: z.number().int().min(5).max(1440).optional(),
// 5 min to 24 hours
includeInactive: z.boolean(),
// Include when no activity
quietHoursRespect: z.boolean()
// Respect quiet hours setting
});
const ScheduleSchema = z.object({
id: z.string().max(32),
config: ScheduleConfigSchema,
enabled: z.boolean(),
lastRun: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/)).optional(),
nextRun: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/)).optional(),
createdAt: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/))
});
const ScheduleStorageSchema = z.object({
schedules: z.array(ScheduleSchema).max(10),
lastChecked: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}T/))
});
const WhatsAppCommandSchema = z.object({
name: z.string().max(50),
description: z.string().max(200),
enabled: z.boolean(),
action: z.string().max(500).optional(),
// Safe action to execute
requiresArg: z.boolean().optional(),
argPattern: z.string().max(100).optional()
// Regex pattern for arg validation
});
const WhatsAppCommandsConfigSchema = z.object({
enabled: z.boolean(),
commands: z.array(WhatsAppCommandSchema).max(50)
});
const ModelProviderSchema = z.enum([
"anthropic",
"qwen",
"openai",
"ollama",
"custom"
]);
const ModelConfigSchema = z.object({
provider: ModelProviderSchema,
model: z.string().max(100),
baseUrl: z.string().url().max(500).optional(),
apiKeyEnv: z.string().max(100),
headers: z.record(z.string().max(500)).optional(),
params: z.record(z.unknown()).optional()
});
const ModelRouterConfigSchema = z.object({
enabled: z.boolean(),
defaultProvider: ModelProviderSchema,
taskRouting: z.object({
plan: ModelProviderSchema.optional(),
think: ModelProviderSchema.optional(),
code: ModelProviderSchema.optional(),
review: ModelProviderSchema.optional()
}).optional().default({}),
fallback: z.object({
enabled: z.boolean(),
provider: ModelProviderSchema,
onRateLimit: z.boolean(),
onError: z.boolean(),
onTimeout: z.boolean(),
maxRetries: z.number().int().min(0).max(10),
retryDelayMs: z.number().int().min(100).max(3e4)
}),
providers: z.object({
anthropic: ModelConfigSchema.optional(),
qwen: ModelConfigSchema.optional(),
openai: ModelConfigSchema.optional(),
ollama: ModelConfigSchema.optional(),
custom: ModelConfigSchema.optional()
}).optional().default({}),
thinkingMode: z.object({
enabled: z.boolean(),
budget: z.number().int().min(1e3).max(1e5).optional(),
temperature: z.number().min(0).max(2).optional(),
topP: z.number().min(0).max(1).optional()
})
});
function parseConfigSafe(schema, data, defaultValue, configName) {
const result = schema.safeParse(data);
if (result.success) {
return result.data;
}
const errors = result.error.issues.map(
(i) => `${i.path.join(".")}: ${i.message}`
);
logConfigInvalid(configName, errors);
console.error(`[hooks] Invalid ${configName} config:`, errors.join(", "));
return defaultValue;
}
export {
ActionQueueSchema,
AutoBackgroundConfigSchema,
ModelConfigSchema,
ModelProviderSchema,
ModelRouterConfigSchema,
NotifyOnSchema,
PendingActionSchema,
PendingPromptSchema,
PromptOptionSchema,
QuietHoursSchema,
SMSConfigSchema,
ScheduleConfigSchema,
ScheduleSchema,
ScheduleStorageSchema,
SyncOptionsSchema,
WhatsAppCommandSchema,
WhatsAppCommandsConfigSchema,
parseConfigSafe
};
//# sourceMappingURL=schemas.js.map