@yamo/memory-mesh 2.3.2 → 3.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 (102) hide show
  1. package/bin/memory_mesh.js +1 -1
  2. package/lib/llm/client.d.ts +111 -0
  3. package/lib/llm/client.js +299 -357
  4. package/lib/llm/client.ts +413 -0
  5. package/lib/llm/index.d.ts +17 -0
  6. package/lib/llm/index.js +15 -8
  7. package/lib/llm/index.ts +19 -0
  8. package/lib/memory/adapters/client.d.ts +183 -0
  9. package/lib/memory/adapters/client.js +518 -0
  10. package/lib/memory/adapters/client.ts +678 -0
  11. package/lib/memory/adapters/config.d.ts +137 -0
  12. package/lib/memory/adapters/config.js +189 -0
  13. package/lib/memory/adapters/config.ts +259 -0
  14. package/lib/memory/adapters/errors.d.ts +76 -0
  15. package/lib/memory/adapters/errors.js +128 -0
  16. package/lib/memory/adapters/errors.ts +166 -0
  17. package/lib/memory/context-manager.d.ts +44 -0
  18. package/lib/memory/context-manager.js +344 -0
  19. package/lib/memory/context-manager.ts +432 -0
  20. package/lib/memory/embeddings/factory.d.ts +59 -0
  21. package/lib/memory/embeddings/factory.js +148 -0
  22. package/lib/{embeddings/factory.js → memory/embeddings/factory.ts} +69 -28
  23. package/lib/memory/embeddings/index.d.ts +2 -0
  24. package/lib/memory/embeddings/index.js +2 -0
  25. package/lib/memory/embeddings/index.ts +2 -0
  26. package/lib/memory/embeddings/service.d.ts +164 -0
  27. package/lib/memory/embeddings/service.js +515 -0
  28. package/lib/{embeddings/service.js → memory/embeddings/service.ts} +223 -156
  29. package/lib/memory/index.d.ts +9 -0
  30. package/lib/memory/index.js +9 -1
  31. package/lib/memory/index.ts +20 -0
  32. package/lib/memory/memory-mesh.d.ts +274 -0
  33. package/lib/memory/memory-mesh.js +1469 -678
  34. package/lib/memory/memory-mesh.ts +1803 -0
  35. package/lib/memory/memory-translator.d.ts +19 -0
  36. package/lib/memory/memory-translator.js +125 -0
  37. package/lib/memory/memory-translator.ts +158 -0
  38. package/lib/memory/schema.d.ts +111 -0
  39. package/lib/memory/schema.js +183 -0
  40. package/lib/memory/schema.ts +267 -0
  41. package/lib/memory/scorer.d.ts +26 -0
  42. package/lib/memory/scorer.js +77 -0
  43. package/lib/memory/scorer.ts +95 -0
  44. package/lib/memory/search/index.d.ts +1 -0
  45. package/lib/memory/search/index.js +1 -0
  46. package/lib/memory/search/index.ts +1 -0
  47. package/lib/memory/search/keyword-search.d.ts +62 -0
  48. package/lib/memory/search/keyword-search.js +135 -0
  49. package/lib/{search/keyword-search.js → memory/search/keyword-search.ts} +66 -36
  50. package/lib/scrubber/config/defaults.d.ts +53 -0
  51. package/lib/scrubber/config/defaults.js +49 -57
  52. package/lib/scrubber/config/defaults.ts +117 -0
  53. package/lib/scrubber/index.d.ts +6 -0
  54. package/lib/scrubber/index.js +3 -23
  55. package/lib/scrubber/index.ts +7 -0
  56. package/lib/scrubber/scrubber.d.ts +61 -0
  57. package/lib/scrubber/scrubber.js +99 -121
  58. package/lib/scrubber/scrubber.ts +168 -0
  59. package/lib/scrubber/stages/chunker.d.ts +13 -0
  60. package/lib/scrubber/stages/metadata-annotator.d.ts +18 -0
  61. package/lib/scrubber/stages/normalizer.d.ts +13 -0
  62. package/lib/scrubber/stages/semantic-filter.d.ts +13 -0
  63. package/lib/scrubber/stages/structural-cleaner.d.ts +13 -0
  64. package/lib/scrubber/stages/validator.d.ts +18 -0
  65. package/lib/scrubber/telemetry.d.ts +36 -0
  66. package/lib/scrubber/telemetry.js +53 -58
  67. package/lib/scrubber/telemetry.ts +99 -0
  68. package/lib/utils/logger.d.ts +29 -0
  69. package/lib/utils/logger.js +64 -0
  70. package/lib/utils/logger.ts +85 -0
  71. package/lib/utils/skill-metadata.d.ts +32 -0
  72. package/lib/utils/skill-metadata.js +132 -0
  73. package/lib/utils/skill-metadata.ts +147 -0
  74. package/lib/yamo/emitter.d.ts +73 -0
  75. package/lib/yamo/emitter.js +78 -143
  76. package/lib/yamo/emitter.ts +249 -0
  77. package/lib/yamo/schema.d.ts +58 -0
  78. package/lib/yamo/schema.js +81 -108
  79. package/lib/yamo/schema.ts +165 -0
  80. package/package.json +11 -8
  81. package/index.d.ts +0 -111
  82. package/lib/embeddings/index.js +0 -2
  83. package/lib/index.js +0 -6
  84. package/lib/lancedb/client.js +0 -633
  85. package/lib/lancedb/config.js +0 -215
  86. package/lib/lancedb/errors.js +0 -144
  87. package/lib/lancedb/index.js +0 -4
  88. package/lib/lancedb/schema.js +0 -217
  89. package/lib/scrubber/errors/scrubber-error.js +0 -43
  90. package/lib/scrubber/stages/chunker.js +0 -103
  91. package/lib/scrubber/stages/metadata-annotator.js +0 -74
  92. package/lib/scrubber/stages/normalizer.js +0 -59
  93. package/lib/scrubber/stages/semantic-filter.js +0 -61
  94. package/lib/scrubber/stages/structural-cleaner.js +0 -82
  95. package/lib/scrubber/stages/validator.js +0 -66
  96. package/lib/scrubber/utils/hash.js +0 -39
  97. package/lib/scrubber/utils/html-parser.js +0 -45
  98. package/lib/scrubber/utils/pattern-matcher.js +0 -63
  99. package/lib/scrubber/utils/token-counter.js +0 -31
  100. package/lib/search/index.js +0 -1
  101. package/lib/utils/index.js +0 -1
  102. package/lib/yamo/index.js +0 -15
@@ -0,0 +1,99 @@
1
+ /**
2
+ * S-MORA Layer 0 Scrubber Telemetry Collection
3
+ * @module smora/scrubber/telemetry
4
+ */
5
+
6
+ export interface StageStats {
7
+ count: number;
8
+ totalTime: number;
9
+ errors: number;
10
+ }
11
+
12
+ export interface StageSummary {
13
+ count: number;
14
+ avgTime: number;
15
+ totalTime: number;
16
+ errors: number;
17
+ }
18
+
19
+ export interface TelemetrySummary {
20
+ stages: Record<string, StageStats>;
21
+ performance: {
22
+ structural: number;
23
+ semantic: number;
24
+ normalization: number;
25
+ chunking: number;
26
+ metadata: number;
27
+ validation: number;
28
+ total: number;
29
+ };
30
+ }
31
+
32
+ export class ScrubberTelemetry {
33
+ stats: Record<string, StageStats>;
34
+
35
+ constructor() {
36
+ this.stats = {
37
+ structural: { count: 0, totalTime: 0, errors: 0 },
38
+ semantic: { count: 0, totalTime: 0, errors: 0 },
39
+ normalization: { count: 0, totalTime: 0, errors: 0 },
40
+ chunking: { count: 0, totalTime: 0, errors: 0 },
41
+ metadata: { count: 0, totalTime: 0, errors: 0 },
42
+ validation: { count: 0, totalTime: 0, errors: 0 },
43
+ };
44
+ }
45
+
46
+ recordStage(stage: string, duration: number, success: boolean = true): void {
47
+ if (!this.stats[stage]) {
48
+ this.stats[stage] = { count: 0, totalTime: 0, errors: 0 };
49
+ }
50
+ this.stats[stage].count++;
51
+ this.stats[stage].totalTime += duration;
52
+ if (!success) {
53
+ this.stats[stage].errors++;
54
+ }
55
+ }
56
+
57
+ getStageStats(stage: string): StageSummary {
58
+ const stats = this.stats[stage] || { count: 0, totalTime: 0, errors: 0 };
59
+ return {
60
+ count: stats.count,
61
+ avgTime: stats.count > 0 ? stats.totalTime / stats.count : 0,
62
+ totalTime: stats.totalTime,
63
+ errors: stats.errors,
64
+ };
65
+ }
66
+
67
+ getSummary(): TelemetrySummary {
68
+ return {
69
+ stages: this.stats,
70
+ performance: {
71
+ structural: this.stats.structural.totalTime,
72
+ semantic: this.stats.semantic.totalTime,
73
+ normalization: this.stats.normalization.totalTime,
74
+ chunking: this.stats.chunking.totalTime,
75
+ metadata: this.stats.metadata.totalTime,
76
+ validation: this.stats.validation.totalTime,
77
+ total: Object.values(this.stats).reduce(
78
+ (sum, s) => sum + s.totalTime,
79
+ 0,
80
+ ),
81
+ },
82
+ };
83
+ }
84
+
85
+ reset(): void {
86
+ Object.keys(this.stats).forEach((key) => {
87
+ this.stats[key] = { count: 0, totalTime: 0, errors: 0 };
88
+ });
89
+ }
90
+
91
+ assertPerformanceBudget(budget: number = 10): void {
92
+ const summary = this.getSummary();
93
+ if (summary.performance.total > budget) {
94
+ throw new Error(
95
+ `Performance budget exceeded: ${summary.performance.total}ms > ${budget}ms`,
96
+ );
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Structured Logger using Pino
3
+ * Provides centralized logging with metadata support, PII redaction, and environment-based formatting
4
+ */
5
+ import pino from "pino";
6
+ /**
7
+ * Main logger instance with configuration
8
+ */
9
+ export declare const logger: pino.Logger<never, boolean>;
10
+ /**
11
+ * Create a child logger with module-specific context
12
+ * @param module - Module name for logging context
13
+ * @returns Child logger instance
14
+ *
15
+ * @example
16
+ * const logger = createLogger('kernel');
17
+ * logger.info({ action: 'boot' }, 'Kernel starting');
18
+ */
19
+ export declare function createLogger(module: string): pino.Logger;
20
+ /**
21
+ * Log levels and their usage:
22
+ * - fatal: Application crash, immediate attention required
23
+ * - error: Errors that need investigation
24
+ * - warn: Degraded state, potential issues
25
+ * - info: Important operational events (default)
26
+ * - debug: Detailed diagnostic information
27
+ * - trace: Very verbose, performance metrics
28
+ */
29
+ export type { Logger } from "pino";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Structured Logger using Pino
3
+ * Provides centralized logging with metadata support, PII redaction, and environment-based formatting
4
+ */
5
+ import pino from "pino";
6
+ // Determine if running in production
7
+ const isProduction = process.env.NODE_ENV === "production";
8
+ const logLevel = (process.env.LOG_LEVEL || "warn");
9
+ /**
10
+ * Main logger instance with configuration
11
+ */
12
+ export const logger = pino({
13
+ level: logLevel,
14
+ // Pretty printing in development, JSON in production
15
+ transport: !isProduction
16
+ ? {
17
+ target: "pino-pretty",
18
+ options: {
19
+ colorize: true,
20
+ translateTime: "HH:MM:ss.l",
21
+ ignore: "pid,hostname,app,version",
22
+ singleLine: false,
23
+ },
24
+ }
25
+ : undefined,
26
+ // Base fields included in all logs
27
+ base: {
28
+ app: "yamo-os",
29
+ version: process.env.npm_package_version || "1.1.0",
30
+ },
31
+ // Redact sensitive fields from logs
32
+ redact: {
33
+ paths: [
34
+ "apiKey",
35
+ "password",
36
+ "token",
37
+ "secret",
38
+ "key",
39
+ "*.apiKey",
40
+ "*.password",
41
+ "*.token",
42
+ "*.secret",
43
+ "*.key",
44
+ "OPENAI_API_KEY",
45
+ "ANTHROPIC_API_KEY",
46
+ "ZAI_API_KEY",
47
+ ],
48
+ censor: "[REDACTED]",
49
+ },
50
+ // Timestamp in ISO format
51
+ timestamp: pino.stdTimeFunctions.isoTime,
52
+ });
53
+ /**
54
+ * Create a child logger with module-specific context
55
+ * @param module - Module name for logging context
56
+ * @returns Child logger instance
57
+ *
58
+ * @example
59
+ * const logger = createLogger('kernel');
60
+ * logger.info({ action: 'boot' }, 'Kernel starting');
61
+ */
62
+ export function createLogger(module) {
63
+ return logger.child({ module });
64
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Structured Logger using Pino
3
+ * Provides centralized logging with metadata support, PII redaction, and environment-based formatting
4
+ */
5
+
6
+ import pino from "pino";
7
+
8
+ // Determine if running in production
9
+ const isProduction = process.env.NODE_ENV === "production";
10
+ const logLevel = (process.env.LOG_LEVEL || "warn") as pino.Level;
11
+
12
+ /**
13
+ * Main logger instance with configuration
14
+ */
15
+ export const logger = pino({
16
+ level: logLevel,
17
+
18
+ // Pretty printing in development, JSON in production
19
+ transport: !isProduction
20
+ ? {
21
+ target: "pino-pretty",
22
+ options: {
23
+ colorize: true,
24
+ translateTime: "HH:MM:ss.l",
25
+ ignore: "pid,hostname,app,version",
26
+ singleLine: false,
27
+ },
28
+ }
29
+ : undefined,
30
+
31
+ // Base fields included in all logs
32
+ base: {
33
+ app: "yamo-os",
34
+ version: process.env.npm_package_version || "1.1.0",
35
+ },
36
+
37
+ // Redact sensitive fields from logs
38
+ redact: {
39
+ paths: [
40
+ "apiKey",
41
+ "password",
42
+ "token",
43
+ "secret",
44
+ "key",
45
+ "*.apiKey",
46
+ "*.password",
47
+ "*.token",
48
+ "*.secret",
49
+ "*.key",
50
+ "OPENAI_API_KEY",
51
+ "ANTHROPIC_API_KEY",
52
+ "ZAI_API_KEY",
53
+ ],
54
+ censor: "[REDACTED]",
55
+ },
56
+
57
+ // Timestamp in ISO format
58
+ timestamp: pino.stdTimeFunctions.isoTime,
59
+ });
60
+
61
+ /**
62
+ * Create a child logger with module-specific context
63
+ * @param module - Module name for logging context
64
+ * @returns Child logger instance
65
+ *
66
+ * @example
67
+ * const logger = createLogger('kernel');
68
+ * logger.info({ action: 'boot' }, 'Kernel starting');
69
+ */
70
+ export function createLogger(module: string): pino.Logger {
71
+ return logger.child({ module });
72
+ }
73
+
74
+ /**
75
+ * Log levels and their usage:
76
+ * - fatal: Application crash, immediate attention required
77
+ * - error: Errors that need investigation
78
+ * - warn: Degraded state, potential issues
79
+ * - info: Important operational events (default)
80
+ * - debug: Detailed diagnostic information
81
+ * - trace: Very verbose, performance metrics
82
+ */
83
+
84
+ // Re-export types for convenience
85
+ export type { Logger } from "pino";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Structured skill-identity extraction.
3
+ *
4
+ * Reads ONLY the YAML frontmatter block (between --- delimiters) or
5
+ * root-level identity declarations in legacy v0.4 compact format.
6
+ * The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
7
+ */
8
+ export interface SkillIdentity {
9
+ name: string;
10
+ intent: string;
11
+ description: string;
12
+ }
13
+ /**
14
+ * Extract identity fields (name, intent, description) from .yamo content.
15
+ *
16
+ * Priority:
17
+ * 1. YAML frontmatter (--- … --- block at file start)
18
+ * 2. Legacy v0.4 root-level compact declarations
19
+ * 3. Content-hash fallback — deterministic and idempotent
20
+ */
21
+ export declare function extractSkillIdentity(content: string): SkillIdentity;
22
+ /**
23
+ * Extract tags from YAML frontmatter.
24
+ * Returns an array of tag strings, or empty array if no tags found.
25
+ *
26
+ * Tags are expected in the format:
27
+ * tags: tag1, tag2, tag3
28
+ *
29
+ * This function ONLY reads the YAML frontmatter block and does NOT parse
30
+ * the skill body, following the same safety constraints as extractSkillIdentity.
31
+ */
32
+ export declare function extractSkillTags(content: string): string[];
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Structured skill-identity extraction.
3
+ *
4
+ * Reads ONLY the YAML frontmatter block (between --- delimiters) or
5
+ * root-level identity declarations in legacy v0.4 compact format.
6
+ * The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
7
+ */
8
+ import crypto from "crypto";
9
+ /** Fields safe to extract for indexing and display. */
10
+ const IDENTITY_FIELDS = new Set(["name", "intent", "description"]);
11
+ /** Pre-computed regexes for legacy root-level identity declarations. */
12
+ const LEGACY_REGEXES = {
13
+ name: /^name[;:]\s*([^;\n]+);?/m,
14
+ intent: /^intent[;:]\s*([^;\n]+);?/m,
15
+ description: /^description[;:]\s*([^;\n]+);?/m,
16
+ };
17
+ /**
18
+ * Parse flat key: value or key; value lines from a text block.
19
+ * Only extracts whitelisted identity fields.
20
+ */
21
+ function parseFlatBlock(block) {
22
+ const result = {};
23
+ for (const line of block.split("\n")) {
24
+ const trimmed = line.trim();
25
+ if (!trimmed || trimmed.startsWith("#")) {
26
+ continue;
27
+ }
28
+ const colonIdx = trimmed.indexOf(":");
29
+ const semiIdx = trimmed.indexOf(";");
30
+ let sepIdx;
31
+ if (colonIdx > 0 && semiIdx > 0) {
32
+ sepIdx = Math.min(colonIdx, semiIdx);
33
+ }
34
+ else if (colonIdx > 0) {
35
+ sepIdx = colonIdx;
36
+ }
37
+ else if (semiIdx > 0) {
38
+ sepIdx = semiIdx;
39
+ }
40
+ else {
41
+ continue;
42
+ }
43
+ const key = trimmed.substring(0, sepIdx).trim();
44
+ let value = trimmed.substring(sepIdx + 1).trim();
45
+ // Strip trailing semicolon (legacy compact format)
46
+ if (value.endsWith(";")) {
47
+ value = value.slice(0, -1).trim();
48
+ }
49
+ if (IDENTITY_FIELDS.has(key) && value) {
50
+ result[key] = value;
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ /**
56
+ * Extract identity fields (name, intent, description) from .yamo content.
57
+ *
58
+ * Priority:
59
+ * 1. YAML frontmatter (--- … --- block at file start)
60
+ * 2. Legacy v0.4 root-level compact declarations
61
+ * 3. Content-hash fallback — deterministic and idempotent
62
+ */
63
+ export function extractSkillIdentity(content) {
64
+ // 1. YAML frontmatter
65
+ if (content.startsWith("---")) {
66
+ const endIdx = content.indexOf("---", 3);
67
+ if (endIdx !== -1) {
68
+ const fields = parseFlatBlock(content.substring(3, endIdx));
69
+ if (fields.name) {
70
+ return {
71
+ name: fields.name,
72
+ intent: fields.intent || "general_procedure",
73
+ description: fields.description || "",
74
+ };
75
+ }
76
+ }
77
+ }
78
+ // 2. Legacy v0.4 root-level identity declarations.
79
+ // Safe: name/intent/description do not appear as body section headers.
80
+ const legacyFields = {};
81
+ for (const field of IDENTITY_FIELDS) {
82
+ const match = content.match(LEGACY_REGEXES[field]);
83
+ if (match) {
84
+ legacyFields[field] = match[1].trim();
85
+ }
86
+ }
87
+ if (legacyFields.name) {
88
+ return {
89
+ name: legacyFields.name,
90
+ intent: legacyFields.intent || "general_procedure",
91
+ description: legacyFields.description || "",
92
+ };
93
+ }
94
+ // 3. Content-hash fallback
95
+ const shortHash = crypto
96
+ .createHash("sha256")
97
+ .update(content)
98
+ .digest("hex")
99
+ .substring(0, 12);
100
+ return {
101
+ name: `Unnamed_${shortHash}`,
102
+ intent: "general_procedure",
103
+ description: "",
104
+ };
105
+ }
106
+ /**
107
+ * Extract tags from YAML frontmatter.
108
+ * Returns an array of tag strings, or empty array if no tags found.
109
+ *
110
+ * Tags are expected in the format:
111
+ * tags: tag1, tag2, tag3
112
+ *
113
+ * This function ONLY reads the YAML frontmatter block and does NOT parse
114
+ * the skill body, following the same safety constraints as extractSkillIdentity.
115
+ */
116
+ export function extractSkillTags(content) {
117
+ // Only parse YAML frontmatter (between --- delimiters)
118
+ if (content.startsWith("---")) {
119
+ const endIdx = content.indexOf("---", 3);
120
+ if (endIdx !== -1) {
121
+ const frontmatter = content.substring(3, endIdx);
122
+ const tagsMatch = frontmatter.match(/^tags:\s*(.+)$/m);
123
+ if (tagsMatch) {
124
+ return tagsMatch[1]
125
+ .split(",")
126
+ .map((t) => t.trim())
127
+ .filter((t) => t.length > 0);
128
+ }
129
+ }
130
+ }
131
+ return [];
132
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Structured skill-identity extraction.
3
+ *
4
+ * Reads ONLY the YAML frontmatter block (between --- delimiters) or
5
+ * root-level identity declarations in legacy v0.4 compact format.
6
+ * The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
7
+ */
8
+
9
+ import crypto from "crypto";
10
+
11
+ export interface SkillIdentity {
12
+ name: string;
13
+ intent: string;
14
+ description: string;
15
+ }
16
+
17
+ /** Fields safe to extract for indexing and display. */
18
+ const IDENTITY_FIELDS = new Set(["name", "intent", "description"]);
19
+
20
+ /** Pre-computed regexes for legacy root-level identity declarations. */
21
+ const LEGACY_REGEXES: Record<string, RegExp> = {
22
+ name: /^name[;:]\s*([^;\n]+);?/m,
23
+ intent: /^intent[;:]\s*([^;\n]+);?/m,
24
+ description: /^description[;:]\s*([^;\n]+);?/m,
25
+ };
26
+
27
+ /**
28
+ * Parse flat key: value or key; value lines from a text block.
29
+ * Only extracts whitelisted identity fields.
30
+ */
31
+ function parseFlatBlock(block: string): Record<string, string> {
32
+ const result: Record<string, string> = {};
33
+ for (const line of block.split("\n")) {
34
+ const trimmed = line.trim();
35
+ if (!trimmed || trimmed.startsWith("#")) {
36
+ continue;
37
+ }
38
+
39
+ const colonIdx = trimmed.indexOf(":");
40
+ const semiIdx = trimmed.indexOf(";");
41
+ let sepIdx: number;
42
+ if (colonIdx > 0 && semiIdx > 0) {
43
+ sepIdx = Math.min(colonIdx, semiIdx);
44
+ } else if (colonIdx > 0) {
45
+ sepIdx = colonIdx;
46
+ } else if (semiIdx > 0) {
47
+ sepIdx = semiIdx;
48
+ } else {
49
+ continue;
50
+ }
51
+
52
+ const key = trimmed.substring(0, sepIdx).trim();
53
+ let value = trimmed.substring(sepIdx + 1).trim();
54
+ // Strip trailing semicolon (legacy compact format)
55
+ if (value.endsWith(";")) {
56
+ value = value.slice(0, -1).trim();
57
+ }
58
+
59
+ if (IDENTITY_FIELDS.has(key) && value) {
60
+ result[key] = value;
61
+ }
62
+ }
63
+ return result;
64
+ }
65
+
66
+ /**
67
+ * Extract identity fields (name, intent, description) from .yamo content.
68
+ *
69
+ * Priority:
70
+ * 1. YAML frontmatter (--- … --- block at file start)
71
+ * 2. Legacy v0.4 root-level compact declarations
72
+ * 3. Content-hash fallback — deterministic and idempotent
73
+ */
74
+ export function extractSkillIdentity(content: string): SkillIdentity {
75
+ // 1. YAML frontmatter
76
+ if (content.startsWith("---")) {
77
+ const endIdx = content.indexOf("---", 3);
78
+ if (endIdx !== -1) {
79
+ const fields = parseFlatBlock(content.substring(3, endIdx));
80
+ if (fields.name) {
81
+ return {
82
+ name: fields.name,
83
+ intent: fields.intent || "general_procedure",
84
+ description: fields.description || "",
85
+ };
86
+ }
87
+ }
88
+ }
89
+
90
+ // 2. Legacy v0.4 root-level identity declarations.
91
+ // Safe: name/intent/description do not appear as body section headers.
92
+ const legacyFields: Record<string, string> = {};
93
+ for (const field of IDENTITY_FIELDS) {
94
+ const match = content.match(LEGACY_REGEXES[field]);
95
+ if (match) {
96
+ legacyFields[field] = match[1].trim();
97
+ }
98
+ }
99
+ if (legacyFields.name) {
100
+ return {
101
+ name: legacyFields.name,
102
+ intent: legacyFields.intent || "general_procedure",
103
+ description: legacyFields.description || "",
104
+ };
105
+ }
106
+
107
+ // 3. Content-hash fallback
108
+ const shortHash = crypto
109
+ .createHash("sha256")
110
+ .update(content)
111
+ .digest("hex")
112
+ .substring(0, 12);
113
+ return {
114
+ name: `Unnamed_${shortHash}`,
115
+ intent: "general_procedure",
116
+ description: "",
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Extract tags from YAML frontmatter.
122
+ * Returns an array of tag strings, or empty array if no tags found.
123
+ *
124
+ * Tags are expected in the format:
125
+ * tags: tag1, tag2, tag3
126
+ *
127
+ * This function ONLY reads the YAML frontmatter block and does NOT parse
128
+ * the skill body, following the same safety constraints as extractSkillIdentity.
129
+ */
130
+ export function extractSkillTags(content: string): string[] {
131
+ // Only parse YAML frontmatter (between --- delimiters)
132
+ if (content.startsWith("---")) {
133
+ const endIdx = content.indexOf("---", 3);
134
+ if (endIdx !== -1) {
135
+ const frontmatter = content.substring(3, endIdx);
136
+ const tagsMatch = frontmatter.match(/^tags:\s*(.+)$/m);
137
+ if (tagsMatch) {
138
+ return tagsMatch[1]
139
+ .split(",")
140
+ .map((t) => t.trim())
141
+ .filter((t) => t.length > 0);
142
+ }
143
+ }
144
+ }
145
+
146
+ return [];
147
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * YAMO Emitter - Constructs structured YAMO blocks for auditability
3
+ *
4
+ * Based on YAMO Protocol specification:
5
+ * - Semicolon-terminated key-value pairs
6
+ * - Agent/Intent/Context/Constraints/Meta/Output structure
7
+ * - Supports reflect, retain, recall operations
8
+ *
9
+ * Reference: Hindsight project's yamo_integration.py
10
+ */
11
+ export interface ReflectBlockParams {
12
+ topic?: string;
13
+ memoryCount: number;
14
+ agentId?: string;
15
+ reflection: string;
16
+ confidence?: number;
17
+ }
18
+ export interface RetainBlockParams {
19
+ content: string;
20
+ metadata?: any;
21
+ id: string;
22
+ agentId?: string;
23
+ memoryType?: string;
24
+ }
25
+ export interface RecallBlockParams {
26
+ query: string;
27
+ resultCount: number;
28
+ limit?: number;
29
+ agentId?: string;
30
+ searchType?: string;
31
+ }
32
+ export interface DeleteBlockParams {
33
+ id: string;
34
+ agentId?: string;
35
+ reason?: string;
36
+ }
37
+ export interface ValidationResult {
38
+ valid: boolean;
39
+ errors: string[];
40
+ }
41
+ /**
42
+ * YamoEmitter class for building YAMO protocol blocks
43
+ * YAMO (Yet Another Multi-agent Orchestration) blocks provide
44
+ * structured reasoning traces for AI agent operations.
45
+ */
46
+ export declare class YamoEmitter {
47
+ /**
48
+ * Build a YAMO block for reflect operation
49
+ * Reflect operations synthesize insights from existing memories
50
+ */
51
+ static buildReflectBlock(params: ReflectBlockParams): string;
52
+ /**
53
+ * Build a YAMO block for retain (add) operation
54
+ * Retain operations store new memories into the system
55
+ */
56
+ static buildRetainBlock(params: RetainBlockParams): string;
57
+ /**
58
+ * Build a YAMO block for recall (search) operation
59
+ * Recall operations retrieve memories based on semantic similarity
60
+ */
61
+ static buildRecallBlock(params: RecallBlockParams): string;
62
+ /**
63
+ * Build a YAMO block for delete operation (optional)
64
+ * Delete operations remove memories from the system
65
+ */
66
+ static buildDeleteBlock(params: DeleteBlockParams): string;
67
+ /**
68
+ * Validate a YAMO block structure
69
+ * Checks for required sections and proper formatting
70
+ */
71
+ static validateBlock(yamoBlock: string): ValidationResult;
72
+ }
73
+ export default YamoEmitter;