comisai 1.0.19 → 1.0.23
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/dist/cli-entry.js +0 -0
- package/node_modules/@comis/agent/dist/context-engine/context-engine.js +43 -2
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +51 -0
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +110 -0
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +54 -0
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +145 -0
- package/node_modules/@comis/agent/dist/context-engine/types-core.d.ts +17 -0
- package/node_modules/@comis/agent/dist/executor/error-classifier.d.ts +11 -1
- package/node_modules/@comis/agent/dist/executor/error-classifier.js +13 -0
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.d.ts +1 -0
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +55 -0
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +106 -5
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +1 -0
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +1 -4
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +30 -3
- package/node_modules/@comis/agent/dist/executor/replay-drift-detector.d.ts +85 -0
- package/node_modules/@comis/agent/dist/executor/replay-drift-detector.js +92 -0
- package/node_modules/@comis/agent/dist/executor/signature-block-scrubber.d.ts +34 -0
- package/node_modules/@comis/agent/dist/executor/signature-block-scrubber.js +69 -0
- package/node_modules/@comis/agent/dist/executor/signed-replay-detector.d.ts +39 -0
- package/node_modules/@comis/agent/dist/executor/signed-replay-detector.js +72 -0
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/cli.js +0 -0
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/config/git-manager.js +10 -4
- package/node_modules/@comis/core/dist/config/index.d.ts +1 -0
- package/node_modules/@comis/core/dist/config/index.js +2 -0
- package/node_modules/@comis/core/dist/config/managed-sections.d.ts +67 -0
- package/node_modules/@comis/core/dist/config/managed-sections.js +124 -0
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +28 -10
- package/node_modules/@comis/core/dist/config/schema-agent.js +6 -0
- package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +2 -2
- package/node_modules/@comis/core/dist/config/schema.d.ts +65 -64
- package/node_modules/@comis/core/dist/event-bus/events-messaging.d.ts +16 -0
- package/node_modules/@comis/core/dist/exports/config.d.ts +1 -1
- package/node_modules/@comis/core/dist/exports/config.js +1 -1
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/init-skill.py +0 -0
- package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/validate-skill.py +0 -0
- package/node_modules/@comis/daemon/dist/daemon.js +11 -4
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.js +20 -7
- package/node_modules/@comis/daemon/dist/rpc/session-handlers.js +27 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.d.ts +22 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +34 -8
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +14 -1
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/dist/logging/log-fields.d.ts +2 -2
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +23 -8
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +18 -14
- package/node_modules/@comis/skills/dist/builtin/platform/unified-session-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/sandbox/detect-provider.d.ts +1 -0
- package/node_modules/@comis/skills/dist/builtin/sandbox/detect-provider.js +78 -5
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +24 -26
- package/node_modules/@comis/agent/dist/provider/response/strip-minimax-xml.d.ts +0 -9
- package/node_modules/@comis/agent/dist/provider/response/strip-minimax-xml.js +0 -17
- package/node_modules/@comis/agent/dist/provider/response/strip-model-tokens.d.ts +0 -13
- package/node_modules/@comis/agent/dist/provider/response/strip-model-tokens.js +0 -19
- package/node_modules/@comis/agent/dist/provider/response/strip-tool-text.d.ts +0 -11
- package/node_modules/@comis/agent/dist/provider/response/strip-tool-text.js +0 -32
- package/node_modules/@comis/agent/dist/safety/follow-through-detector.d.ts +0 -46
- package/node_modules/@comis/agent/dist/safety/follow-through-detector.js +0 -76
- package/node_modules/@comis/agent/dist/safety/post-compaction-safety.d.ts +0 -30
- package/node_modules/@comis/agent/dist/safety/post-compaction-safety.js +0 -51
- package/node_modules/@comis/agent/dist/safety/schema-normalizer.d.ts +0 -37
- package/node_modules/@comis/agent/dist/safety/schema-normalizer.js +0 -137
- package/node_modules/@comis/agent/dist/safety/schema-pruning.d.ts +0 -50
- package/node_modules/@comis/agent/dist/safety/schema-pruning.js +0 -112
- package/node_modules/@comis/agent/dist/safety/tool-image-sanitizer.d.ts +0 -43
- package/node_modules/@comis/agent/dist/safety/tool-image-sanitizer.js +0 -96
- package/node_modules/@comis/agent/dist/safety/tool-sanitizer.d.ts +0 -44
- package/node_modules/@comis/agent/dist/safety/tool-sanitizer.js +0 -94
- package/node_modules/@comis/channels/dist/shared/thinking-tag-filter.d.ts +0 -28
- package/node_modules/@comis/channels/dist/shared/thinking-tag-filter.js +0 -206
- package/node_modules/@comis/cli/dist/wizard/config-writer.d.ts +0 -25
- package/node_modules/@comis/cli/dist/wizard/config-writer.js +0 -144
- package/node_modules/@comis/cli/dist/wizard/flow-types.d.ts +0 -48
- package/node_modules/@comis/cli/dist/wizard/flow-types.js +0 -70
- package/node_modules/@comis/cli/dist/wizard/manual-flow.d.ts +0 -21
- package/node_modules/@comis/cli/dist/wizard/manual-flow.js +0 -345
- package/node_modules/@comis/cli/dist/wizard/quickstart-flow.d.ts +0 -21
- package/node_modules/@comis/cli/dist/wizard/quickstart-flow.js +0 -116
- package/node_modules/@comis/core/dist/config/schema-agent-model.d.ts +0 -135
- package/node_modules/@comis/core/dist/config/schema-agent-model.js +0 -114
- package/node_modules/@comis/core/dist/config/schema-agent-session.d.ts +0 -177
- package/node_modules/@comis/core/dist/config/schema-agent-session.js +0 -116
- package/node_modules/@comis/core/dist/config/schema-context-engine.d.ts +0 -92
- package/node_modules/@comis/core/dist/config/schema-context-engine.js +0 -92
- package/node_modules/@comis/core/dist/config/schema-context-guard.d.ts +0 -34
- package/node_modules/@comis/core/dist/config/schema-context-guard.js +0 -32
- package/node_modules/@comis/core/dist/config/schema-delivery-mirror.d.ts +0 -27
- package/node_modules/@comis/core/dist/config/schema-delivery-mirror.js +0 -26
- package/node_modules/@comis/core/dist/config/schema-delivery-queue.d.ts +0 -31
- package/node_modules/@comis/core/dist/config/schema-delivery-queue.js +0 -30
- package/node_modules/@comis/core/dist/config/schema-delivery-timing.d.ts +0 -41
- package/node_modules/@comis/core/dist/config/schema-delivery-timing.js +0 -31
- package/node_modules/@comis/core/dist/config/schema-monitoring.d.ts +0 -105
- package/node_modules/@comis/core/dist/config/schema-monitoring.js +0 -67
- package/node_modules/@comis/core/dist/ports/media-ports.d.ts +0 -278
- package/node_modules/@comis/core/dist/ports/media-ports.js +0 -1
- package/node_modules/@comis/core/dist/security/input-guard.d.ts +0 -46
- package/node_modules/@comis/core/dist/security/input-guard.js +0 -166
- package/node_modules/@comis/core/dist/security/scoped-secret-manager.d.ts +0 -38
- package/node_modules/@comis/core/dist/security/scoped-secret-manager.js +0 -94
- package/node_modules/@comis/daemon/dist/observability/delivery-context.d.ts +0 -37
- package/node_modules/@comis/daemon/dist/observability/delivery-context.js +0 -1
- package/node_modules/@comis/daemon/dist/observability/log-level-manager.d.ts +0 -23
- package/node_modules/@comis/daemon/dist/observability/log-level-manager.js +0 -34
- package/node_modules/@comis/daemon/dist/observability/log-transport.d.ts +0 -44
- package/node_modules/@comis/daemon/dist/observability/log-transport.js +0 -74
- package/node_modules/@comis/daemon/dist/observability/obs-write-buffer.d.ts +0 -53
- package/node_modules/@comis/daemon/dist/observability/obs-write-buffer.js +0 -68
- package/node_modules/@comis/daemon/dist/observability/types.d.ts +0 -6
- package/node_modules/@comis/daemon/dist/observability/types.js +0 -1
- package/node_modules/@comis/daemon/dist/wiring/seed-bundled-skills.d.ts +0 -41
- package/node_modules/@comis/daemon/dist/wiring/seed-bundled-skills.js +0 -84
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery-mirror.d.ts +0 -24
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery-mirror.js +0 -88
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery-queue.d.ts +0 -31
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery-queue.js +0 -132
- package/node_modules/@comis/daemon/dist/wiring/setup-monitoring.d.ts +0 -38
- package/node_modules/@comis/daemon/dist/wiring/setup-monitoring.js +0 -100
- package/node_modules/@comis/daemon/dist/wiring/setup-rpc-bridge.d.ts +0 -34
- package/node_modules/@comis/daemon/dist/wiring/setup-rpc-bridge.js +0 -52
- package/node_modules/@comis/daemon/dist/wiring/setup-task-extraction.d.ts +0 -41
- package/node_modules/@comis/daemon/dist/wiring/setup-task-extraction.js +0 -86
- package/node_modules/@comis/memory/dist/embedding-cache.d.ts +0 -36
- package/node_modules/@comis/memory/dist/embedding-cache.js +0 -94
- package/node_modules/@comis/skills/dist/bridge/tool-output-schemas.d.ts +0 -17
- package/node_modules/@comis/skills/dist/bridge/tool-output-schemas.js +0 -125
- package/node_modules/@comis/skills/dist/bridge/tool-parallelism-metadata.d.ts +0 -14
- package/node_modules/@comis/skills/dist/bridge/tool-parallelism-metadata.js +0 -92
- package/node_modules/@comis/skills/dist/bridge/tool-result-caps.d.ts +0 -14
- package/node_modules/@comis/skills/dist/bridge/tool-result-caps.js +0 -36
- package/node_modules/@comis/skills/dist/bridge/tool-search-hints.d.ts +0 -15
- package/node_modules/@comis/skills/dist/bridge/tool-search-hints.js +0 -68
- package/node_modules/@comis/skills/dist/bridge/tool-validators.d.ts +0 -11
- package/node_modules/@comis/skills/dist/bridge/tool-validators.js +0 -105
- package/node_modules/@comis/skills/dist/builtin/file/find-sort-wrapper.d.ts +0 -22
- package/node_modules/@comis/skills/dist/builtin/file/find-sort-wrapper.js +0 -95
- package/node_modules/@comis/skills/dist/builtin/file/grep-output-mode-wrapper.d.ts +0 -24
- package/node_modules/@comis/skills/dist/builtin/file/grep-output-mode-wrapper.js +0 -167
- package/node_modules/@comis/skills/dist/builtin/task-plan-tool.d.ts +0 -25
- package/node_modules/@comis/skills/dist/builtin/task-plan-tool.js +0 -67
- package/node_modules/@comis/skills/dist/integrations/mcp-tool-bridge.d.ts +0 -75
- package/node_modules/@comis/skills/dist/integrations/mcp-tool-bridge.js +0 -235
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InputGuard — Semantic jailbreak detection with weighted 0.0-1.0 threat scoring.
|
|
3
|
-
*
|
|
4
|
-
* Factory function that creates a guard object with a `scan()` method. Detects
|
|
5
|
-
* jailbreak attempts using weighted compound phrase patterns imported from
|
|
6
|
-
* `injection-patterns.ts`, typoglycemia detection for 8 key terms, and code
|
|
7
|
-
* block exclusion to minimize false positives on technical content.
|
|
8
|
-
*
|
|
9
|
-
* Returns scored results that PiExecutor uses for policy decisions:
|
|
10
|
-
* - low risk (< mediumThreshold) -> action "pass"
|
|
11
|
-
* - medium risk (>= mediumThreshold, < highThreshold) -> action "reinforce"
|
|
12
|
-
* - high risk (>= highThreshold) -> action "warn" (default) or "block" (config)
|
|
13
|
-
*
|
|
14
|
-
* @module input-guard
|
|
15
|
-
* @since Phase 283 (INPUT-03 through INPUT-06)
|
|
16
|
-
*/
|
|
17
|
-
export interface InputGuardConfig {
|
|
18
|
-
/** Threat score threshold for "medium" risk (triggers reinforcement). Default: 0.4. */
|
|
19
|
-
readonly mediumThreshold: number;
|
|
20
|
-
/** Threat score threshold for "high" risk (triggers warn/block). Default: 0.7. */
|
|
21
|
-
readonly highThreshold: number;
|
|
22
|
-
/** Action for high-risk detections. Default: "warn". "block" requires explicit config. */
|
|
23
|
-
readonly action: "warn" | "block";
|
|
24
|
-
}
|
|
25
|
-
export interface InputGuardResult {
|
|
26
|
-
/** Threat score clamped to 0.0-1.0. */
|
|
27
|
-
readonly score: number;
|
|
28
|
-
/** Risk level derived from score vs thresholds. */
|
|
29
|
-
readonly riskLevel: "low" | "medium" | "high";
|
|
30
|
-
/** Matched pattern category names. */
|
|
31
|
-
readonly patterns: string[];
|
|
32
|
-
/** Recommended policy action. */
|
|
33
|
-
readonly action: "pass" | "warn" | "reinforce" | "block";
|
|
34
|
-
}
|
|
35
|
-
export interface InputGuard {
|
|
36
|
-
scan(text: string): InputGuardResult;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Create an InputGuard that scores user input text for jailbreak risk.
|
|
40
|
-
*
|
|
41
|
-
* Configuration is optional; all fields have sensible defaults:
|
|
42
|
-
* - mediumThreshold: 0.4
|
|
43
|
-
* - highThreshold: 0.7
|
|
44
|
-
* - action: "warn" (operator must explicitly set "block" to enable blocking)
|
|
45
|
-
*/
|
|
46
|
-
export declare function createInputGuard(config?: Partial<InputGuardConfig>): InputGuard;
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InputGuard — Semantic jailbreak detection with weighted 0.0-1.0 threat scoring.
|
|
3
|
-
*
|
|
4
|
-
* Factory function that creates a guard object with a `scan()` method. Detects
|
|
5
|
-
* jailbreak attempts using weighted compound phrase patterns imported from
|
|
6
|
-
* `injection-patterns.ts`, typoglycemia detection for 8 key terms, and code
|
|
7
|
-
* block exclusion to minimize false positives on technical content.
|
|
8
|
-
*
|
|
9
|
-
* Returns scored results that PiExecutor uses for policy decisions:
|
|
10
|
-
* - low risk (< mediumThreshold) -> action "pass"
|
|
11
|
-
* - medium risk (>= mediumThreshold, < highThreshold) -> action "reinforce"
|
|
12
|
-
* - high risk (>= highThreshold) -> action "warn" (default) or "block" (config)
|
|
13
|
-
*
|
|
14
|
-
* @module input-guard
|
|
15
|
-
* @since Phase 283 (INPUT-03 through INPUT-06)
|
|
16
|
-
*/
|
|
17
|
-
import { IGNORE_PREV_INSTRUCTIONS, IGNORE_INSTRUCTIONS_BROAD, DISREGARD_PREVIOUS, DISREGARD_INSTRUCTIONS, FORGET_EVERYTHING, FORGET_INSTRUCTIONS_BROAD, YOU_ARE_NOW, YOU_ARE_NOW_ARTICLE, NEW_INSTRUCTIONS, NEW_INSTRUCTIONS_COLON, IMPORTANT_OVERRIDE, OVERRIDE_SAFETY, ACT_AS_ROLE, CONTEXT_RESET, RULE_REPLACEMENT, SYSTEM_TAG, SYSTEM_BRACKET, SYSTEM_COMMAND, SPECIAL_TOKEN_DELIMITERS, ROLE_BOUNDARY, ASSISTANT_ROLE_MARKER, } from "./injection-patterns.js";
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
// Weighted pattern categories (Pattern 6 from research)
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
/**
|
|
22
|
-
* Each category groups related regex patterns with a single weight.
|
|
23
|
-
* If ANY pattern in a category matches, the weight is added once (boolean per category).
|
|
24
|
-
* Multiple matches within the same category do NOT multiply the weight.
|
|
25
|
-
*/
|
|
26
|
-
const PATTERN_WEIGHTS = [
|
|
27
|
-
{ patterns: [IGNORE_PREV_INSTRUCTIONS, IGNORE_INSTRUCTIONS_BROAD], weight: 0.6, name: "ignore_instructions" },
|
|
28
|
-
{ patterns: [DISREGARD_PREVIOUS, DISREGARD_INSTRUCTIONS], weight: 0.5, name: "disregard_previous" },
|
|
29
|
-
{ patterns: [FORGET_EVERYTHING, FORGET_INSTRUCTIONS_BROAD], weight: 0.5, name: "forget_instructions" },
|
|
30
|
-
{ patterns: [YOU_ARE_NOW, YOU_ARE_NOW_ARTICLE], weight: 0.4, name: "role_assumption" },
|
|
31
|
-
{ patterns: [NEW_INSTRUCTIONS, NEW_INSTRUCTIONS_COLON], weight: 0.5, name: "new_instructions" },
|
|
32
|
-
{ patterns: [IMPORTANT_OVERRIDE], weight: 0.5, name: "important_override" },
|
|
33
|
-
{ patterns: [OVERRIDE_SAFETY], weight: 0.6, name: "override_safety" },
|
|
34
|
-
{ patterns: [ACT_AS_ROLE], weight: 0.4, name: "act_as_role" },
|
|
35
|
-
{ patterns: [CONTEXT_RESET], weight: 0.4, name: "context_reset" },
|
|
36
|
-
{ patterns: [RULE_REPLACEMENT], weight: 0.4, name: "rule_replacement" },
|
|
37
|
-
{ patterns: [SYSTEM_TAG, SYSTEM_BRACKET, SYSTEM_COMMAND], weight: 0.3, name: "system_markers" },
|
|
38
|
-
{ patterns: [SPECIAL_TOKEN_DELIMITERS], weight: 0.3, name: "special_tokens" },
|
|
39
|
-
{ patterns: [ROLE_BOUNDARY, ASSISTANT_ROLE_MARKER], weight: 0.2, name: "role_markers" },
|
|
40
|
-
];
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
// Code block exclusion (INPUT-06)
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
/**
|
|
45
|
-
* Regex to match fenced code blocks (triple backtick) and inline code (single backtick).
|
|
46
|
-
* ReDoS-safe: [\s\S]*? is non-greedy character class without alternation.
|
|
47
|
-
*/
|
|
48
|
-
const CODE_BLOCK_REGEX = /```[\s\S]*?```|`[^`\n]+`/g;
|
|
49
|
-
function stripCodeBlocks(text) {
|
|
50
|
-
CODE_BLOCK_REGEX.lastIndex = 0;
|
|
51
|
-
return text.replace(CODE_BLOCK_REGEX, " ");
|
|
52
|
-
}
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
// Typoglycemia detection (INPUT-05)
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
/**
|
|
57
|
-
* The 8 key jailbreak terms to check for scrambled-middle variants.
|
|
58
|
-
* All are 5+ characters long, ensuring sufficient middle-letter entropy
|
|
59
|
-
* to avoid false positives on short words.
|
|
60
|
-
*/
|
|
61
|
-
const TYPOGLYCEMIA_TERMS = [
|
|
62
|
-
"ignore",
|
|
63
|
-
"previous",
|
|
64
|
-
"instructions",
|
|
65
|
-
"system",
|
|
66
|
-
"bypass",
|
|
67
|
-
"override",
|
|
68
|
-
"forget",
|
|
69
|
-
"delete",
|
|
70
|
-
];
|
|
71
|
-
/**
|
|
72
|
-
* Check whether a word is a typoglycemia variant of a target term.
|
|
73
|
-
*
|
|
74
|
-
* A word is a variant if:
|
|
75
|
-
* 1. Same length as target
|
|
76
|
-
* 2. Same first character (case-insensitive)
|
|
77
|
-
* 3. Same last character (case-insensitive)
|
|
78
|
-
* 4. NOT an exact match (exact matches are handled by regex patterns)
|
|
79
|
-
* 5. Same sorted middle characters
|
|
80
|
-
*
|
|
81
|
-
* This implements the "Cambridge University effect" where human readers
|
|
82
|
-
* can understand words with scrambled middle letters.
|
|
83
|
-
*/
|
|
84
|
-
function isTypoglycemiaVariant(word, target) {
|
|
85
|
-
if (word.length !== target.length)
|
|
86
|
-
return false;
|
|
87
|
-
const w = word.toLowerCase();
|
|
88
|
-
const t = target.toLowerCase();
|
|
89
|
-
if (w[0] !== t[0] || w[w.length - 1] !== t[t.length - 1])
|
|
90
|
-
return false;
|
|
91
|
-
if (w === t)
|
|
92
|
-
return false; // Exact match is NOT a variant
|
|
93
|
-
const wMiddle = [...w.slice(1, -1)].sort().join("");
|
|
94
|
-
const tMiddle = [...t.slice(1, -1)].sort().join("");
|
|
95
|
-
return wMiddle === tMiddle;
|
|
96
|
-
}
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
// Factory function
|
|
99
|
-
// ---------------------------------------------------------------------------
|
|
100
|
-
/**
|
|
101
|
-
* Create an InputGuard that scores user input text for jailbreak risk.
|
|
102
|
-
*
|
|
103
|
-
* Configuration is optional; all fields have sensible defaults:
|
|
104
|
-
* - mediumThreshold: 0.4
|
|
105
|
-
* - highThreshold: 0.7
|
|
106
|
-
* - action: "warn" (operator must explicitly set "block" to enable blocking)
|
|
107
|
-
*/
|
|
108
|
-
export function createInputGuard(config) {
|
|
109
|
-
const mediumThreshold = config?.mediumThreshold ?? 0.4;
|
|
110
|
-
const highThreshold = config?.highThreshold ?? 0.7;
|
|
111
|
-
const action = config?.action ?? "warn";
|
|
112
|
-
return {
|
|
113
|
-
scan(text) {
|
|
114
|
-
const stripped = stripCodeBlocks(text);
|
|
115
|
-
const matched = [];
|
|
116
|
-
let score = 0;
|
|
117
|
-
// 1. Weighted pattern category matching
|
|
118
|
-
for (const category of PATTERN_WEIGHTS) {
|
|
119
|
-
let categoryMatched = false;
|
|
120
|
-
for (const pattern of category.patterns) {
|
|
121
|
-
// Reset lastIndex before each test() call (patterns have /g or /gi flags)
|
|
122
|
-
pattern.lastIndex = 0;
|
|
123
|
-
if (pattern.test(stripped)) {
|
|
124
|
-
categoryMatched = true;
|
|
125
|
-
break; // Category is boolean -- one match suffices
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (categoryMatched) {
|
|
129
|
-
score += category.weight;
|
|
130
|
-
matched.push(category.name);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// 2. Typoglycemia detection
|
|
134
|
-
const words = stripped.split(/\s+/);
|
|
135
|
-
for (const word of words) {
|
|
136
|
-
if (word.length === 0)
|
|
137
|
-
continue;
|
|
138
|
-
for (const term of TYPOGLYCEMIA_TERMS) {
|
|
139
|
-
if (isTypoglycemiaVariant(word, term)) {
|
|
140
|
-
matched.push(`typoglycemia:${term}`);
|
|
141
|
-
score += 0.3;
|
|
142
|
-
break; // One word matches at most one term
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// 3. Clamp score to [0.0, 1.0]
|
|
147
|
-
score = Math.min(score, 1.0);
|
|
148
|
-
// 4. Determine risk level
|
|
149
|
-
const riskLevel = score >= highThreshold ? "high"
|
|
150
|
-
: score >= mediumThreshold ? "medium"
|
|
151
|
-
: "low";
|
|
152
|
-
// 5. Determine action
|
|
153
|
-
let resultAction;
|
|
154
|
-
if (riskLevel === "high") {
|
|
155
|
-
resultAction = action === "block" ? "block" : "warn";
|
|
156
|
-
}
|
|
157
|
-
else if (riskLevel === "medium") {
|
|
158
|
-
resultAction = "reinforce";
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
resultAction = "pass";
|
|
162
|
-
}
|
|
163
|
-
return { score, riskLevel, patterns: matched, action: resultAction };
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScopedSecretManager — per-agent SecretManager decorator with glob filtering.
|
|
3
|
-
*
|
|
4
|
-
* Wraps a base SecretManager and restricts access to secrets matching
|
|
5
|
-
* the agent's allow patterns. Every access attempt (get, has, require)
|
|
6
|
-
* emits a `secret:accessed` audit event through the optional TypedEventBus.
|
|
7
|
-
*
|
|
8
|
-
* Design decisions:
|
|
9
|
-
* - Decorator pattern: callers cannot distinguish from a plain SecretManager
|
|
10
|
-
* - Empty allowPatterns = unrestricted access (backward compat for existing agents)
|
|
11
|
-
* - eventBus is optional: if omitted, no audit events are emitted (unit-test friendly)
|
|
12
|
-
* - keys() filters but does not emit (listing operation, not access)
|
|
13
|
-
*/
|
|
14
|
-
import type { SecretManager } from "./secret-manager.js";
|
|
15
|
-
import type { TypedEventBus } from "../event-bus/index.js";
|
|
16
|
-
/**
|
|
17
|
-
* Options for creating a scoped (per-agent) SecretManager.
|
|
18
|
-
*/
|
|
19
|
-
export interface ScopedSecretManagerOptions {
|
|
20
|
-
/** The agent this scoped manager belongs to. Included in all audit events. */
|
|
21
|
-
agentId: string;
|
|
22
|
-
/** Glob patterns that grant access. Empty array = unrestricted (backward compat). */
|
|
23
|
-
allowPatterns: string[];
|
|
24
|
-
/** Optional event bus for audit event emission. No-op if omitted. */
|
|
25
|
-
eventBus?: TypedEventBus;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Create a SecretManager that filters access by glob patterns and emits audit events.
|
|
29
|
-
*
|
|
30
|
-
* The returned object implements the SecretManager interface exactly — same 4 methods
|
|
31
|
-
* (get, has, require, keys), same return types. This is the decorator pattern:
|
|
32
|
-
* callers cannot distinguish a ScopedSecretManager from a plain SecretManager.
|
|
33
|
-
*
|
|
34
|
-
* @param base - The underlying SecretManager to delegate allowed accesses to
|
|
35
|
-
* @param options - Agent ID, allow patterns, and optional event bus
|
|
36
|
-
* @returns A SecretManager that enforces per-agent access control
|
|
37
|
-
*/
|
|
38
|
-
export declare function createScopedSecretManager(base: SecretManager, options: ScopedSecretManagerOptions): SecretManager;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ScopedSecretManager — per-agent SecretManager decorator with glob filtering.
|
|
3
|
-
*
|
|
4
|
-
* Wraps a base SecretManager and restricts access to secrets matching
|
|
5
|
-
* the agent's allow patterns. Every access attempt (get, has, require)
|
|
6
|
-
* emits a `secret:accessed` audit event through the optional TypedEventBus.
|
|
7
|
-
*
|
|
8
|
-
* Design decisions:
|
|
9
|
-
* - Decorator pattern: callers cannot distinguish from a plain SecretManager
|
|
10
|
-
* - Empty allowPatterns = unrestricted access (backward compat for existing agents)
|
|
11
|
-
* - eventBus is optional: if omitted, no audit events are emitted (unit-test friendly)
|
|
12
|
-
* - keys() filters but does not emit (listing operation, not access)
|
|
13
|
-
*/
|
|
14
|
-
import { isSecretAccessible } from "./secret-access.js";
|
|
15
|
-
/**
|
|
16
|
-
* Create a SecretManager that filters access by glob patterns and emits audit events.
|
|
17
|
-
*
|
|
18
|
-
* The returned object implements the SecretManager interface exactly — same 4 methods
|
|
19
|
-
* (get, has, require, keys), same return types. This is the decorator pattern:
|
|
20
|
-
* callers cannot distinguish a ScopedSecretManager from a plain SecretManager.
|
|
21
|
-
*
|
|
22
|
-
* @param base - The underlying SecretManager to delegate allowed accesses to
|
|
23
|
-
* @param options - Agent ID, allow patterns, and optional event bus
|
|
24
|
-
* @returns A SecretManager that enforces per-agent access control
|
|
25
|
-
*/
|
|
26
|
-
export function createScopedSecretManager(base, options) {
|
|
27
|
-
const { agentId, allowPatterns, eventBus } = options;
|
|
28
|
-
let warnedNoAllow = false;
|
|
29
|
-
/**
|
|
30
|
-
* Emit a one-time security:warn event when an agent accesses secrets
|
|
31
|
-
* without explicit secrets.allow configuration (CORE-02).
|
|
32
|
-
*/
|
|
33
|
-
function warnUnrestrictedAccess(secretName) {
|
|
34
|
-
if (warnedNoAllow || allowPatterns.length > 0 || !eventBus)
|
|
35
|
-
return;
|
|
36
|
-
warnedNoAllow = true;
|
|
37
|
-
eventBus.emit("security:warn", {
|
|
38
|
-
category: "secret_access",
|
|
39
|
-
agentId,
|
|
40
|
-
message: `Agent "${agentId}" accessed secret "${secretName}" without explicit secrets.allow configuration. ` +
|
|
41
|
-
`Configure secrets.allow patterns to restrict access.`,
|
|
42
|
-
timestamp: Date.now(),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
function emitAccess(secretName, outcome) {
|
|
46
|
-
eventBus?.emit("secret:accessed", {
|
|
47
|
-
secretName,
|
|
48
|
-
agentId,
|
|
49
|
-
outcome,
|
|
50
|
-
timestamp: Date.now(),
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
get(key) {
|
|
55
|
-
warnUnrestrictedAccess(key);
|
|
56
|
-
if (!isSecretAccessible(key, allowPatterns)) {
|
|
57
|
-
emitAccess(key, "denied");
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
const value = base.get(key);
|
|
61
|
-
emitAccess(key, value !== undefined ? "success" : "not_found");
|
|
62
|
-
return value;
|
|
63
|
-
},
|
|
64
|
-
has(key) {
|
|
65
|
-
warnUnrestrictedAccess(key);
|
|
66
|
-
if (!isSecretAccessible(key, allowPatterns)) {
|
|
67
|
-
emitAccess(key, "denied");
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
const exists = base.has(key);
|
|
71
|
-
emitAccess(key, exists ? "success" : "not_found");
|
|
72
|
-
return exists;
|
|
73
|
-
},
|
|
74
|
-
require(key) {
|
|
75
|
-
warnUnrestrictedAccess(key);
|
|
76
|
-
if (!isSecretAccessible(key, allowPatterns)) {
|
|
77
|
-
emitAccess(key, "denied");
|
|
78
|
-
throw new Error(`Agent "${agentId}" is not allowed to access secret "${key}". ` +
|
|
79
|
-
`Check the agent's secrets.allow configuration.`);
|
|
80
|
-
}
|
|
81
|
-
const value = base.get(key);
|
|
82
|
-
if (value === undefined) {
|
|
83
|
-
emitAccess(key, "not_found");
|
|
84
|
-
throw new Error(`Required secret "${key}" is not set. ` +
|
|
85
|
-
`Check that this key is defined in your .env file or encrypted store.`);
|
|
86
|
-
}
|
|
87
|
-
emitAccess(key, "success");
|
|
88
|
-
return value;
|
|
89
|
-
},
|
|
90
|
-
keys() {
|
|
91
|
-
return base.keys().filter((k) => isSecretAccessible(k, allowPatterns));
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DeliveryContext: metadata captured per message delivery for tracing (OBS-04).
|
|
3
|
-
*
|
|
4
|
-
* Records source/target channel identifiers, delivery timing, success status,
|
|
5
|
-
* and optional attribution (agent, session). Downstream consumers use this
|
|
6
|
-
* for delivery tracing dashboards and latency analysis.
|
|
7
|
-
*/
|
|
8
|
-
export interface DeliveryContext {
|
|
9
|
-
/** Source channel that originated the message */
|
|
10
|
-
sourceChannelId: string;
|
|
11
|
-
sourceChannelType: string;
|
|
12
|
-
/** Delivery target */
|
|
13
|
-
targetChannelId: string;
|
|
14
|
-
targetChannelType: string;
|
|
15
|
-
/** Timestamp when delivery was initiated */
|
|
16
|
-
deliveredAt: number;
|
|
17
|
-
/** Time from message receipt to delivery completion in ms */
|
|
18
|
-
latencyMs: number;
|
|
19
|
-
/** Whether delivery succeeded */
|
|
20
|
-
success: boolean;
|
|
21
|
-
/** Error message if delivery failed */
|
|
22
|
-
error?: string;
|
|
23
|
-
/** Agent that processed the message */
|
|
24
|
-
agentId?: string;
|
|
25
|
-
/** Session key string */
|
|
26
|
-
sessionKey?: string;
|
|
27
|
-
/** Execution timeline steps synthesized from timing data */
|
|
28
|
-
steps?: Array<{
|
|
29
|
-
name: string;
|
|
30
|
-
timestamp: number;
|
|
31
|
-
durationMs: number;
|
|
32
|
-
status: "ok" | "error";
|
|
33
|
-
error?: string;
|
|
34
|
-
}>;
|
|
35
|
-
/** Additional metadata (retry count, parse mode fallback, etc.) */
|
|
36
|
-
metadata?: Record<string, unknown>;
|
|
37
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type ComisLogger } from "@comis/infra";
|
|
2
|
-
/**
|
|
3
|
-
* Log level manager: per-module child loggers with runtime level control.
|
|
4
|
-
*
|
|
5
|
-
* Modules obtain their logger via getLogger(module), which returns a cached
|
|
6
|
-
* Pino child logger. Levels can be changed at runtime per-module or globally
|
|
7
|
-
* via the daemon.setLogLevel RPC (OBS-04).
|
|
8
|
-
*/
|
|
9
|
-
export interface LogLevelManager {
|
|
10
|
-
/** Get or create a child logger for a named module. Cached on first call. */
|
|
11
|
-
getLogger(module: string): ComisLogger;
|
|
12
|
-
/** Change the log level for a specific module's logger. */
|
|
13
|
-
setLevel(module: string, level: string): void;
|
|
14
|
-
/** Change the root logger's level (affects all modules that haven't been individually overridden). */
|
|
15
|
-
setGlobalLevel(level: string): void;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Create a log level manager that maintains a registry of per-module child loggers.
|
|
19
|
-
*
|
|
20
|
-
* @param rootLogger - The root Pino logger from which child loggers are derived
|
|
21
|
-
* @returns A LogLevelManager instance
|
|
22
|
-
*/
|
|
23
|
-
export declare function createLogLevelManager(rootLogger: ComisLogger): LogLevelManager;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { isValidLogLevel } from "@comis/infra";
|
|
2
|
-
/**
|
|
3
|
-
* Create a log level manager that maintains a registry of per-module child loggers.
|
|
4
|
-
*
|
|
5
|
-
* @param rootLogger - The root Pino logger from which child loggers are derived
|
|
6
|
-
* @returns A LogLevelManager instance
|
|
7
|
-
*/
|
|
8
|
-
export function createLogLevelManager(rootLogger) {
|
|
9
|
-
const loggers = new Map();
|
|
10
|
-
const manager = {
|
|
11
|
-
getLogger(module) {
|
|
12
|
-
let logger = loggers.get(module);
|
|
13
|
-
if (!logger) {
|
|
14
|
-
logger = rootLogger.child({ module });
|
|
15
|
-
loggers.set(module, logger);
|
|
16
|
-
}
|
|
17
|
-
return logger;
|
|
18
|
-
},
|
|
19
|
-
setLevel(module, level) {
|
|
20
|
-
if (!isValidLogLevel(level))
|
|
21
|
-
return; // CRED-05: silently reject invalid levels
|
|
22
|
-
const logger = loggers.get(module);
|
|
23
|
-
if (logger) {
|
|
24
|
-
logger.level = level;
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
setGlobalLevel(level) {
|
|
28
|
-
if (!isValidLogLevel(level))
|
|
29
|
-
return; // CRED-05: silently reject invalid levels
|
|
30
|
-
rootLogger.level = level;
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
return manager;
|
|
34
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Log transport factory: constructs pino multi-target transport config
|
|
3
|
-
* for simultaneous file rotation (pino-roll) and stdout output.
|
|
4
|
-
*
|
|
5
|
-
* INFRA-02: File rotation transport.
|
|
6
|
-
* INFRA-03: Dual file + stdout output.
|
|
7
|
-
* INFRA-04: removeOtherLogFiles cleanup.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import type { LoggingConfig } from "@comis/core";
|
|
12
|
-
import type pino from "pino";
|
|
13
|
-
/**
|
|
14
|
-
* Expand leading tilde to os.homedir().
|
|
15
|
-
* pino-roll does NOT expand tildes, so this must be called before
|
|
16
|
-
* passing filePath to the transport.
|
|
17
|
-
*/
|
|
18
|
-
export declare function expandTilde(filePath: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* Detect whether the process is running under pm2.
|
|
21
|
-
*
|
|
22
|
-
* pm2 sets the `PM2_HOME` environment variable for all managed processes.
|
|
23
|
-
* When running under pm2, stdout is already captured to pm2's own log files
|
|
24
|
-
* (`~/.pm2/logs/`), so the pino-roll file transport would be a byte-for-byte
|
|
25
|
-
* duplicate.
|
|
26
|
-
*/
|
|
27
|
-
export declare function isPm2Managed(): boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Create a pino multi-target transport config from LoggingConfig.
|
|
30
|
-
*
|
|
31
|
-
* LI-1: PM2-aware transport selection.
|
|
32
|
-
* - File transport (pino-roll): always active -- canonical log location.
|
|
33
|
-
* - Stdout: skipped under pm2 (PM2_HOME set) to avoid byte-for-byte
|
|
34
|
-
* duplication with pm2's own log capture in ~/.pm2/logs/.
|
|
35
|
-
*
|
|
36
|
-
* Note: node-llama-cpp native module warnings write directly to stderr and
|
|
37
|
-
* cannot be captured by Pino transports. This is a known limitation.
|
|
38
|
-
*
|
|
39
|
-
* @param config - Logging config from DaemonConfigSchema.logging
|
|
40
|
-
* @param level - Log level to apply to each target (Pino multi-transport
|
|
41
|
-
* targets default to "info" unless explicitly set)
|
|
42
|
-
* @returns Transport config to pass as LoggerOptions.transport
|
|
43
|
-
*/
|
|
44
|
-
export declare function createFileTransport(config: LoggingConfig, level?: string): pino.TransportMultiOptions;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Log transport factory: constructs pino multi-target transport config
|
|
3
|
-
* for simultaneous file rotation (pino-roll) and stdout output.
|
|
4
|
-
*
|
|
5
|
-
* INFRA-02: File rotation transport.
|
|
6
|
-
* INFRA-03: Dual file + stdout output.
|
|
7
|
-
* INFRA-04: removeOtherLogFiles cleanup.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import os from "node:os";
|
|
12
|
-
/**
|
|
13
|
-
* Expand leading tilde to os.homedir().
|
|
14
|
-
* pino-roll does NOT expand tildes, so this must be called before
|
|
15
|
-
* passing filePath to the transport.
|
|
16
|
-
*/
|
|
17
|
-
export function expandTilde(filePath) {
|
|
18
|
-
return filePath.replace(/^~(?=\/|$)/, os.homedir());
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Detect whether the process is running under pm2.
|
|
22
|
-
*
|
|
23
|
-
* pm2 sets the `PM2_HOME` environment variable for all managed processes.
|
|
24
|
-
* When running under pm2, stdout is already captured to pm2's own log files
|
|
25
|
-
* (`~/.pm2/logs/`), so the pino-roll file transport would be a byte-for-byte
|
|
26
|
-
* duplicate.
|
|
27
|
-
*/
|
|
28
|
-
export function isPm2Managed() {
|
|
29
|
-
return typeof process.env.PM2_HOME === "string" && process.env.PM2_HOME.length > 0;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Create a pino multi-target transport config from LoggingConfig.
|
|
33
|
-
*
|
|
34
|
-
* LI-1: PM2-aware transport selection.
|
|
35
|
-
* - File transport (pino-roll): always active -- canonical log location.
|
|
36
|
-
* - Stdout: skipped under pm2 (PM2_HOME set) to avoid byte-for-byte
|
|
37
|
-
* duplication with pm2's own log capture in ~/.pm2/logs/.
|
|
38
|
-
*
|
|
39
|
-
* Note: node-llama-cpp native module warnings write directly to stderr and
|
|
40
|
-
* cannot be captured by Pino transports. This is a known limitation.
|
|
41
|
-
*
|
|
42
|
-
* @param config - Logging config from DaemonConfigSchema.logging
|
|
43
|
-
* @param level - Log level to apply to each target (Pino multi-transport
|
|
44
|
-
* targets default to "info" unless explicitly set)
|
|
45
|
-
* @returns Transport config to pass as LoggerOptions.transport
|
|
46
|
-
*/
|
|
47
|
-
export function createFileTransport(config, level) {
|
|
48
|
-
const expandedPath = expandTilde(config.filePath);
|
|
49
|
-
const pm2Detected = isPm2Managed();
|
|
50
|
-
const targets = [];
|
|
51
|
-
// File transport: always active -- ~/.comis/logs/ is the canonical log location
|
|
52
|
-
targets.push({
|
|
53
|
-
target: "pino-roll",
|
|
54
|
-
options: {
|
|
55
|
-
file: expandedPath,
|
|
56
|
-
size: config.maxSize,
|
|
57
|
-
mkdir: true,
|
|
58
|
-
limit: {
|
|
59
|
-
count: config.maxFiles,
|
|
60
|
-
removeOtherLogFiles: true,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
...(level ? { level } : {}),
|
|
64
|
-
});
|
|
65
|
-
// Stdout: skip under pm2 (pm2 captures stdout to ~/.pm2/logs/, so it would be a duplicate)
|
|
66
|
-
if (!pm2Detected) {
|
|
67
|
-
targets.push({
|
|
68
|
-
target: "pino/file",
|
|
69
|
-
options: { destination: 1 }, // stdout
|
|
70
|
-
...(level ? { level } : {}),
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return { targets };
|
|
74
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic batched write buffer for observability persistence.
|
|
3
|
-
*
|
|
4
|
-
* Sits between event bus listeners and ObservabilityStore: listeners push items
|
|
5
|
-
* into the buffer; the buffer flushes batches to SQLite periodically or when
|
|
6
|
-
* the buffer reaches its size threshold.
|
|
7
|
-
*
|
|
8
|
-
* Design:
|
|
9
|
-
* - Plain array (not ring buffer) per research recommendation
|
|
10
|
-
* - Dual trigger: size threshold (default 50) OR timer interval (default 500ms)
|
|
11
|
-
* - Timer uses unref() so it does not prevent Node.js process exit
|
|
12
|
-
* - drain() provides synchronous final flush for clean shutdown
|
|
13
|
-
* - flushFn is synchronous (better-sqlite3 db.transaction() is sync)
|
|
14
|
-
*
|
|
15
|
-
* @module obs-write-buffer
|
|
16
|
-
*/
|
|
17
|
-
/** Public interface for the write buffer. */
|
|
18
|
-
export interface ObsWriteBuffer<T> {
|
|
19
|
-
/** Add an item to the buffer. Triggers flush if buffer hits maxSize. */
|
|
20
|
-
push(item: T): void;
|
|
21
|
-
/** Flush current buffer contents to the flush callback. No-op if empty. */
|
|
22
|
-
flush(): void;
|
|
23
|
-
/** Synchronous final flush for shutdown: flushes remaining items and clears the interval timer. */
|
|
24
|
-
drain(): void;
|
|
25
|
-
/** Number of items currently buffered. */
|
|
26
|
-
readonly pending: number;
|
|
27
|
-
}
|
|
28
|
-
/** Options for creating a write buffer. */
|
|
29
|
-
export interface ObsWriteBufferOptions<T> {
|
|
30
|
-
/** Callback invoked with a batch of items when flushing. Must be synchronous (better-sqlite3 is sync). */
|
|
31
|
-
flushFn: (items: T[]) => void;
|
|
32
|
-
/** Maximum buffer size before triggering a flush. Default: 50. */
|
|
33
|
-
maxSize?: number;
|
|
34
|
-
/** Interval in ms between automatic flushes. Default: 500. */
|
|
35
|
-
intervalMs?: number;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Create a generic batched write buffer.
|
|
39
|
-
*
|
|
40
|
-
* Usage:
|
|
41
|
-
* ```ts
|
|
42
|
-
* const buf = createObsWriteBuffer<TokenUsageRow>({
|
|
43
|
-
* flushFn: (items) => store.insertTokenUsageBatch(items),
|
|
44
|
-
* maxSize: 50,
|
|
45
|
-
* intervalMs: 500,
|
|
46
|
-
* });
|
|
47
|
-
*
|
|
48
|
-
* eventBus.on("token:usage", (entry) => buf.push(toRow(entry)));
|
|
49
|
-
* // On shutdown:
|
|
50
|
-
* buf.drain();
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export declare function createObsWriteBuffer<T>(opts: ObsWriteBufferOptions<T>): ObsWriteBuffer<T>;
|