@alsania-io/scribe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @alsania-io/scribe
2
+
3
+ > Markdown-based audit logging with redaction for Alsania ecosystem
4
+
5
+ ## Features
6
+
7
+ - 📝 **Markdown-based logs** — Human-readable, version-control friendly
8
+ - 🔒 **Automatic redaction** — Sensitive fields (API keys, passwords, tokens) are redacted
9
+ - 📅 **Session-based organization** — Logs organized by date and session
10
+ - 🔗 **Anchoring support** — SHA3-256 hashing for on-chain verification
11
+ - 🎨 **Configurable templates** — Customizable header and entry formats
12
+ - 🚀 **Zero dependencies** — Pure TypeScript, no external dependencies
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @alsania-io/scribe
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import { Scribe } from '@alsania-io/scribe';
24
+
25
+ const scribe = new Scribe({
26
+ root: './logs',
27
+ redact: ['Authorization', 'api_key', 'password']
28
+ });
29
+
30
+ // Start a session
31
+ scribe.session('session-123', {
32
+ owner: 'Sigma',
33
+ model: 'echo-cloud',
34
+ mcpUrl: 'http://localhost:8050/mcp'
35
+ });
36
+
37
+ // Log different types of entries
38
+ scribe.prompt('What is the meaning of life?');
39
+ scribe.response('The meaning of life is 42.');
40
+ scribe.toolCall('calculator', { expression: '2 + 2' }, 4);
41
+ scribe.error('Something went wrong');
42
+ scribe.event('connection_established', { peer: 'Aegis' });
43
+
44
+ // Get the latest log file
45
+ const latest = scribe.getLatestLog();
46
+ console.log(`Log file: ${latest}`);
47
+
48
+ // Anchor the log (for on-chain verification)
49
+ const anchor = scribe.anchorLatest();
50
+ console.log(`Hash: ${anchor.hash}`);
51
+
52
+ // Get all anchors
53
+ const anchors = scribe.getAnchors();
54
+ console.log(anchors);
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ```typescript
60
+ const config = {
61
+ // Root directory for logs
62
+ root: './logs',
63
+
64
+ // Log format (only 'markdown' for now)
65
+ mode: 'markdown',
66
+
67
+ // Automatically log tokens and patches
68
+ autoLogTokens: true,
69
+ autoLogPatches: true,
70
+
71
+ // Fields to redact
72
+ redact: ['Authorization', 'api_key', 'password', 'secret'],
73
+
74
+ // Header template for new sessions
75
+ headerTemplate: `# Scribe — {{date}} ({{session}})
76
+
77
+ **Owner:** {{owner}}
78
+ **Model:** {{model}}
79
+ **MCP:** {{mcp}}
80
+
81
+ ---`,
82
+
83
+ // Entry template
84
+ entryTemplate: `## {{time}} — {{type}}
85
+
86
+ {{content}}
87
+ `
88
+ };
89
+ ```
90
+
91
+ ## API
92
+
93
+ ### `new Scribe(config?)`
94
+ Create a new Scribe instance.
95
+
96
+ ### `scribe.session(id, context?)`
97
+ Start a new session. All subsequent logs will be written to this session.
98
+
99
+ ### `scribe.prompt(content, metadata?)`
100
+ Log a user prompt.
101
+
102
+ ### `scribe.response(content, metadata?)`
103
+ Log an AI response.
104
+
105
+ ### `scribe.toolCall(toolName, args, result?)`
106
+ Log a tool call with arguments and result.
107
+
108
+ ### `scribe.error(message, stack?, metadata?)`
109
+ Log an error with optional stack trace.
110
+
111
+ ### `scribe.event(name, data?)`
112
+ Log a custom event.
113
+
114
+ ### `scribe.write(entry)`
115
+ Write a raw entry.
116
+
117
+ ### `scribe.getLatestLog()`
118
+ Get the path to the latest log file.
119
+
120
+ ### `scribe.hashLog(filePath)`
121
+ Compute SHA3-256 hash of a log file.
122
+
123
+ ### `scribe.anchorLatest()`
124
+ Anchor the latest log file (creates an anchor record).
125
+
126
+ ### `scribe.getAnchors()`
127
+ Get all anchor records.
128
+
129
+ ## Integration with Alsania Projects
130
+
131
+ ### AlsaniaMCP
132
+ ```typescript
133
+ import { Scribe } from '@alsania-io/scribe';
134
+
135
+ const scribe = new Scribe({ root: '/var/log/alsaniamcp' });
136
+ scribe.session(serverId, { owner: 'Sigma', model: 'echo-cloud' });
137
+ ```
138
+
139
+ ### DevConX
140
+ ```typescript
141
+ import { Scribe } from '@alsania-io/scribe';
142
+
143
+ const scribe = new Scribe({ root: '~/.devcon/logs' });
144
+ scribe.session(extensionSession, { owner: 'Sigma' });
145
+ ```
146
+
147
+ ### Nyx
148
+ ```typescript
149
+ import { Scribe } from '@alsania-io/scribe';
150
+
151
+ const scribe = new Scribe({ root: '~/.nyx/logs' });
152
+ scribe.session(browserSession, { owner: 'Sigma' });
153
+ ```
154
+
155
+ ## License
156
+
157
+ MIT
@@ -0,0 +1,145 @@
1
+ /**
2
+ * @alsania-io/scribe
3
+ * Markdown-based audit logging with redaction for Alsania ecosystem
4
+ *
5
+ * Features:
6
+ * - Markdown-based log entries with timestamps and session tracking
7
+ * - Automatic redaction of sensitive fields (API keys, passwords, tokens)
8
+ * - Session-based log organization
9
+ * - Configurable header and entry templates
10
+ * - Anchor support for on-chain verification
11
+ */
12
+ /**
13
+ * Scribe configuration
14
+ */
15
+ export interface ScribeConfig {
16
+ /** Root directory for log storage */
17
+ root: string;
18
+ /** Log format (currently only 'markdown') */
19
+ mode?: 'markdown';
20
+ /** Automatically log tokens */
21
+ autoLogTokens?: boolean;
22
+ /** Automatically log patches */
23
+ autoLogPatches?: boolean;
24
+ /** Sensitive fields to redact */
25
+ redact?: string[];
26
+ /** Header template for new session logs */
27
+ headerTemplate?: string;
28
+ /** Entry template for each log entry */
29
+ entryTemplate?: string;
30
+ }
31
+ /**
32
+ * Scribe session context
33
+ */
34
+ export interface ScribeSession {
35
+ id: string;
36
+ owner?: string;
37
+ model?: string;
38
+ mcpUrl?: string;
39
+ }
40
+ /**
41
+ * Scribe entry
42
+ */
43
+ export interface ScribeEntry {
44
+ timestamp: Date;
45
+ type: string;
46
+ content: string;
47
+ metadata?: Record<string, any>;
48
+ }
49
+ /**
50
+ * Scribe class for markdown-based audit logging
51
+ */
52
+ export declare class Scribe {
53
+ private config;
54
+ private currentSession;
55
+ private logDir;
56
+ constructor(config?: Partial<ScribeConfig>);
57
+ /**
58
+ * Ensure the log directory exists
59
+ */
60
+ private ensureLogDir;
61
+ /**
62
+ * Get the log directory path
63
+ */
64
+ getLogDir(): string;
65
+ /**
66
+ * Start a new session or set the current session
67
+ */
68
+ session(sessionId: string, context?: Partial<ScribeSession>): this;
69
+ /**
70
+ * Get the current session ID
71
+ */
72
+ getSessionId(): string | null;
73
+ /**
74
+ * Get the session log file path
75
+ */
76
+ private getSessionPath;
77
+ /**
78
+ * Redact sensitive content
79
+ */
80
+ private redact;
81
+ /**
82
+ * Write a log entry to the current session
83
+ */
84
+ write(entry: ScribeEntry | string, type?: string): void;
85
+ /**
86
+ * Initialize a session file with header
87
+ */
88
+ private initializeSessionFile;
89
+ /**
90
+ * Format a log entry
91
+ */
92
+ private formatEntry;
93
+ /**
94
+ * Log a prompt
95
+ */
96
+ prompt(content: string, metadata?: Record<string, any>): void;
97
+ /**
98
+ * Log a response
99
+ */
100
+ response(content: string, metadata?: Record<string, any>): void;
101
+ /**
102
+ * Log a tool call
103
+ */
104
+ toolCall(toolName: string, args: any, result?: any): void;
105
+ /**
106
+ * Log an error
107
+ */
108
+ error(message: string, stack?: string, metadata?: Record<string, any>): void;
109
+ /**
110
+ * Log an event
111
+ */
112
+ event(name: string, data?: any): void;
113
+ /**
114
+ * Get the latest session log file
115
+ */
116
+ getLatestLog(): string | null;
117
+ /**
118
+ * Compute SHA3-256 hash of a log file (for anchoring)
119
+ */
120
+ hashLog(filePath: string): string;
121
+ /**
122
+ * Anchor the latest log (creates an anchor record)
123
+ */
124
+ anchorLatest(): {
125
+ file: string;
126
+ hash: string;
127
+ } | null;
128
+ /**
129
+ * Get all anchor records
130
+ */
131
+ getAnchors(): {
132
+ timestamp: number;
133
+ file: string;
134
+ hash: string;
135
+ }[];
136
+ }
137
+ /**
138
+ * Create a new Scribe instance
139
+ */
140
+ export declare function createScribe(config?: Partial<ScribeConfig>): Scribe;
141
+ /**
142
+ * Default export
143
+ */
144
+ export default Scribe;
145
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,307 @@
1
+ "use strict";
2
+ /**
3
+ * @alsania-io/scribe
4
+ * Markdown-based audit logging with redaction for Alsania ecosystem
5
+ *
6
+ * Features:
7
+ * - Markdown-based log entries with timestamps and session tracking
8
+ * - Automatic redaction of sensitive fields (API keys, passwords, tokens)
9
+ * - Session-based log organization
10
+ * - Configurable header and entry templates
11
+ * - Anchor support for on-chain verification
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.Scribe = void 0;
48
+ exports.createScribe = createScribe;
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
51
+ const crypto_1 = require("crypto");
52
+ /**
53
+ * Default configuration
54
+ */
55
+ const DEFAULT_CONFIG = {
56
+ root: './logs',
57
+ mode: 'markdown',
58
+ autoLogTokens: true,
59
+ autoLogPatches: true,
60
+ redact: ['Authorization', 'api_key', 'bearer', 'password', 'secret', 'token', 'X-Alsania-Sig'],
61
+ headerTemplate: `# Scribe — {{date}} ({{session}})
62
+
63
+ **Owner:** {{owner}}
64
+ **Model:** {{model}}
65
+ **MCP:** {{mcp}}
66
+
67
+ ---
68
+ `,
69
+ entryTemplate: `## {{time}} — {{type}}
70
+
71
+ {{content}}
72
+
73
+ `,
74
+ };
75
+ /**
76
+ * Scribe class for markdown-based audit logging
77
+ */
78
+ class Scribe {
79
+ constructor(config = {}) {
80
+ this.currentSession = null;
81
+ this.config = { ...DEFAULT_CONFIG, ...config };
82
+ this.logDir = path.resolve(this.config.root);
83
+ this.ensureLogDir();
84
+ }
85
+ /**
86
+ * Ensure the log directory exists
87
+ */
88
+ ensureLogDir() {
89
+ if (!fs.existsSync(this.logDir)) {
90
+ fs.mkdirSync(this.logDir, { recursive: true });
91
+ }
92
+ }
93
+ /**
94
+ * Get the log directory path
95
+ */
96
+ getLogDir() {
97
+ return this.logDir;
98
+ }
99
+ /**
100
+ * Start a new session or set the current session
101
+ */
102
+ session(sessionId, context) {
103
+ this.currentSession = {
104
+ id: sessionId,
105
+ owner: context?.owner || 'Unknown',
106
+ model: context?.model || 'Unknown',
107
+ mcpUrl: context?.mcpUrl || 'Unknown',
108
+ };
109
+ return this;
110
+ }
111
+ /**
112
+ * Get the current session ID
113
+ */
114
+ getSessionId() {
115
+ return this.currentSession?.id || null;
116
+ }
117
+ /**
118
+ * Get the session log file path
119
+ */
120
+ getSessionPath(sessionId) {
121
+ const date = new Date().toISOString().split('T')[0];
122
+ const sessionDir = path.join(this.logDir, date);
123
+ if (!fs.existsSync(sessionDir)) {
124
+ fs.mkdirSync(sessionDir, { recursive: true });
125
+ }
126
+ return path.join(sessionDir, `${sessionId}.md`);
127
+ }
128
+ /**
129
+ * Redact sensitive content
130
+ */
131
+ redact(content) {
132
+ let redacted = content;
133
+ const patterns = this.config.redact || [];
134
+ for (const pattern of patterns) {
135
+ // Handle both exact matches and regex-like patterns
136
+ if (pattern.includes('*') || pattern.includes('[')) {
137
+ // Simple wildcard support
138
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'), 'gi');
139
+ redacted = redacted.replace(regex, '■redacted■');
140
+ }
141
+ else {
142
+ // Exact string match
143
+ redacted = redacted.replace(new RegExp(pattern, 'gi'), '■redacted■');
144
+ }
145
+ }
146
+ return redacted;
147
+ }
148
+ /**
149
+ * Write a log entry to the current session
150
+ */
151
+ write(entry, type) {
152
+ const sessionId = this.currentSession?.id;
153
+ if (!sessionId) {
154
+ throw new Error('No active session. Call .session() first.');
155
+ }
156
+ const content = typeof entry === 'string' ? entry : entry.content;
157
+ const entryType = typeof entry === 'string' ? type || 'log' : entry.type;
158
+ const timestamp = typeof entry === 'string' ? new Date() : entry.timestamp;
159
+ const metadata = typeof entry === 'string' ? undefined : entry.metadata;
160
+ const redactedContent = this.redact(content);
161
+ const filePath = this.getSessionPath(sessionId);
162
+ // Initialize session file if it doesn't exist
163
+ if (!fs.existsSync(filePath)) {
164
+ this.initializeSessionFile(filePath);
165
+ }
166
+ // Format and append the entry
167
+ const entryText = this.formatEntry(timestamp, entryType, redactedContent);
168
+ fs.appendFileSync(filePath, entryText, 'utf-8');
169
+ }
170
+ /**
171
+ * Initialize a session file with header
172
+ */
173
+ initializeSessionFile(filePath) {
174
+ const session = this.currentSession;
175
+ if (!session)
176
+ return;
177
+ const date = new Date().toISOString().split('T')[0];
178
+ let header = this.config.headerTemplate || DEFAULT_CONFIG.headerTemplate;
179
+ header = header
180
+ .replace(/{{date}}/g, date)
181
+ .replace(/{{session}}/g, session.id)
182
+ .replace(/{{owner}}/g, session.owner || 'Unknown')
183
+ .replace(/{{model}}/g, session.model || 'Unknown')
184
+ .replace(/{{mcp}}/g, session.mcpUrl || 'Unknown');
185
+ fs.writeFileSync(filePath, header, 'utf-8');
186
+ }
187
+ /**
188
+ * Format a log entry
189
+ */
190
+ formatEntry(timestamp, type, content) {
191
+ const timeStr = timestamp.toISOString().split('T')[1].split('.')[0];
192
+ let entry = this.config.entryTemplate || DEFAULT_CONFIG.entryTemplate;
193
+ entry = entry
194
+ .replace(/{{time}}/g, timeStr)
195
+ .replace(/{{type}}/g, type)
196
+ .replace(/{{content}}/g, content);
197
+ return entry;
198
+ }
199
+ /**
200
+ * Log a prompt
201
+ */
202
+ prompt(content, metadata) {
203
+ this.write({ timestamp: new Date(), type: 'prompt', content, metadata });
204
+ }
205
+ /**
206
+ * Log a response
207
+ */
208
+ response(content, metadata) {
209
+ this.write({ timestamp: new Date(), type: 'response', content, metadata });
210
+ }
211
+ /**
212
+ * Log a tool call
213
+ */
214
+ toolCall(toolName, args, result) {
215
+ const content = JSON.stringify({ tool: toolName, args, result }, null, 2);
216
+ this.write({ timestamp: new Date(), type: `tool:${toolName}`, content });
217
+ }
218
+ /**
219
+ * Log an error
220
+ */
221
+ error(message, stack, metadata) {
222
+ const content = stack ? `${message}\n\n${stack}` : message;
223
+ this.write({ timestamp: new Date(), type: 'error', content, metadata });
224
+ }
225
+ /**
226
+ * Log an event
227
+ */
228
+ event(name, data) {
229
+ const content = data ? JSON.stringify(data, null, 2) : name;
230
+ this.write({ timestamp: new Date(), type: `event:${name}`, content });
231
+ }
232
+ /**
233
+ * Get the latest session log file
234
+ */
235
+ getLatestLog() {
236
+ const dirs = fs.readdirSync(this.logDir)
237
+ .filter((d) => fs.statSync(path.join(this.logDir, d)).isDirectory())
238
+ .sort()
239
+ .reverse();
240
+ for (const dir of dirs) {
241
+ const dirPath = path.join(this.logDir, dir);
242
+ const files = fs.readdirSync(dirPath)
243
+ .filter((f) => f.endsWith('.md'))
244
+ .sort()
245
+ .reverse();
246
+ if (files.length > 0) {
247
+ return path.join(dirPath, files[0]);
248
+ }
249
+ }
250
+ return null;
251
+ }
252
+ /**
253
+ * Compute SHA3-256 hash of a log file (for anchoring)
254
+ */
255
+ hashLog(filePath) {
256
+ const content = fs.readFileSync(filePath);
257
+ const hash = (0, crypto_1.createHash)('sha3-256');
258
+ hash.update(content);
259
+ return '0x' + hash.digest('hex');
260
+ }
261
+ /**
262
+ * Anchor the latest log (creates an anchor record)
263
+ */
264
+ anchorLatest() {
265
+ const latest = this.getLatestLog();
266
+ if (!latest)
267
+ return null;
268
+ const hash = this.hashLog(latest);
269
+ const anchorsDir = path.join(this.logDir, '_anchors');
270
+ if (!fs.existsSync(anchorsDir)) {
271
+ fs.mkdirSync(anchorsDir, { recursive: true });
272
+ }
273
+ const anchorLog = path.join(anchorsDir, 'anchors.log');
274
+ const entry = `${Date.now()},${path.basename(latest)},${hash}\n`;
275
+ fs.appendFileSync(anchorLog, entry, 'utf-8');
276
+ return { file: latest, hash };
277
+ }
278
+ /**
279
+ * Get all anchor records
280
+ */
281
+ getAnchors() {
282
+ const anchorsDir = path.join(this.logDir, '_anchors');
283
+ const anchorLog = path.join(anchorsDir, 'anchors.log');
284
+ if (!fs.existsSync(anchorLog))
285
+ return [];
286
+ const content = fs.readFileSync(anchorLog, 'utf-8');
287
+ return content
288
+ .split('\n')
289
+ .filter((line) => line.trim())
290
+ .map((line) => {
291
+ const [timestamp, file, hash] = line.split(',');
292
+ return { timestamp: parseInt(timestamp), file, hash };
293
+ });
294
+ }
295
+ }
296
+ exports.Scribe = Scribe;
297
+ /**
298
+ * Create a new Scribe instance
299
+ */
300
+ function createScribe(config) {
301
+ return new Scribe(config);
302
+ }
303
+ /**
304
+ * Default export
305
+ */
306
+ exports.default = Scribe;
307
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@alsania-io/scribe",
3
+ "version": "0.1.0",
4
+ "description": "Markdown-based audit logging with redaction for Alsania ecosystem",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "clean": "rm -rf dist",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "logging",
21
+ "audit",
22
+ "markdown",
23
+ "redaction",
24
+ "alsania",
25
+ "scribe"
26
+ ],
27
+ "author": "Alsania I/O <admin@alsania-io.com>",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/alsania-dev/alsania-io-utils.git"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md"
36
+ ],
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^20.0.0",
42
+ "typescript": "^5.0.0"
43
+ }
44
+ }