@jungjaehoon/mama-os 0.41.0 → 0.43.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 (103) hide show
  1. package/dist/agent/agent-loop.d.ts +2 -0
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js +37 -0
  4. package/dist/agent/agent-loop.js.map +1 -1
  5. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  6. package/dist/agent/code-act/host-bridge.js +45 -0
  7. package/dist/agent/code-act/host-bridge.js.map +1 -1
  8. package/dist/agent/gateway-tool-executor.d.ts +15 -0
  9. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  10. package/dist/agent/gateway-tool-executor.js +217 -0
  11. package/dist/agent/gateway-tool-executor.js.map +1 -1
  12. package/dist/agent/gateway-tools.md +3 -0
  13. package/dist/agent/tool-registry.d.ts.map +1 -1
  14. package/dist/agent/tool-registry.js +18 -0
  15. package/dist/agent/tool-registry.js.map +1 -1
  16. package/dist/agent/types.d.ts +18 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/agent/types.js.map +1 -1
  19. package/dist/api/graph-api.d.ts.map +1 -1
  20. package/dist/api/graph-api.js +23 -4
  21. package/dist/api/graph-api.js.map +1 -1
  22. package/dist/cli/commands/start.d.ts.map +1 -1
  23. package/dist/cli/commands/start.js +179 -0
  24. package/dist/cli/commands/start.js.map +1 -1
  25. package/dist/cli/config/types.d.ts +6 -0
  26. package/dist/cli/config/types.d.ts.map +1 -1
  27. package/dist/cli/config/types.js +2 -0
  28. package/dist/cli/config/types.js.map +1 -1
  29. package/dist/cli/runtime/agent-loop-init.d.ts +4 -0
  30. package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
  31. package/dist/cli/runtime/agent-loop-init.js +7 -0
  32. package/dist/cli/runtime/agent-loop-init.js.map +1 -1
  33. package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
  34. package/dist/cli/runtime/mama-core-init.js +2 -0
  35. package/dist/cli/runtime/mama-core-init.js.map +1 -1
  36. package/dist/evidence/effects.d.ts +7 -6
  37. package/dist/evidence/effects.d.ts.map +1 -1
  38. package/dist/evidence/effects.js +60 -1
  39. package/dist/evidence/effects.js.map +1 -1
  40. package/dist/gateways/context-injector.d.ts +10 -0
  41. package/dist/gateways/context-injector.d.ts.map +1 -1
  42. package/dist/gateways/context-injector.js.map +1 -1
  43. package/dist/gateways/message-router.d.ts +4 -0
  44. package/dist/gateways/message-router.d.ts.map +1 -1
  45. package/dist/gateways/message-router.js +86 -2
  46. package/dist/gateways/message-router.js.map +1 -1
  47. package/dist/observability/operational-issues.d.ts +55 -0
  48. package/dist/observability/operational-issues.d.ts.map +1 -0
  49. package/dist/observability/operational-issues.js +170 -0
  50. package/dist/observability/operational-issues.js.map +1 -0
  51. package/dist/operator/file-export.d.ts +22 -0
  52. package/dist/operator/file-export.d.ts.map +1 -0
  53. package/dist/operator/file-export.js +115 -0
  54. package/dist/operator/file-export.js.map +1 -0
  55. package/dist/operator/learning-context.d.ts +49 -0
  56. package/dist/operator/learning-context.d.ts.map +1 -0
  57. package/dist/operator/learning-context.js +129 -0
  58. package/dist/operator/learning-context.js.map +1 -0
  59. package/dist/operator/learning-markers.d.ts +19 -0
  60. package/dist/operator/learning-markers.d.ts.map +1 -0
  61. package/dist/operator/learning-markers.js +147 -0
  62. package/dist/operator/learning-markers.js.map +1 -0
  63. package/dist/operator/learning-read.d.ts +16 -0
  64. package/dist/operator/learning-read.d.ts.map +1 -0
  65. package/dist/operator/learning-read.js +18 -0
  66. package/dist/operator/learning-read.js.map +1 -0
  67. package/dist/operator/owner-event-loop.d.ts +6 -0
  68. package/dist/operator/owner-event-loop.d.ts.map +1 -1
  69. package/dist/operator/owner-event-loop.js +12 -1
  70. package/dist/operator/owner-event-loop.js.map +1 -1
  71. package/dist/operator/owner-event-prompt.d.ts +2 -0
  72. package/dist/operator/owner-event-prompt.d.ts.map +1 -1
  73. package/dist/operator/owner-event-prompt.js +1 -0
  74. package/dist/operator/owner-event-prompt.js.map +1 -1
  75. package/dist/operator/repair-request.d.ts +29 -0
  76. package/dist/operator/repair-request.d.ts.map +1 -0
  77. package/dist/operator/repair-request.js +115 -0
  78. package/dist/operator/repair-request.js.map +1 -0
  79. package/dist/operator/report-context.d.ts +13 -0
  80. package/dist/operator/report-context.d.ts.map +1 -1
  81. package/dist/operator/report-context.js +39 -1
  82. package/dist/operator/report-context.js.map +1 -1
  83. package/dist/operator/task-ledger.d.ts +24 -1
  84. package/dist/operator/task-ledger.d.ts.map +1 -1
  85. package/dist/operator/task-ledger.js +64 -1
  86. package/dist/operator/task-ledger.js.map +1 -1
  87. package/dist/operator/turn-observer.d.ts +34 -0
  88. package/dist/operator/turn-observer.d.ts.map +1 -0
  89. package/dist/operator/turn-observer.js +79 -0
  90. package/dist/operator/turn-observer.js.map +1 -0
  91. package/dist/operator/worker-run.d.ts +4 -0
  92. package/dist/operator/worker-run.d.ts.map +1 -1
  93. package/dist/operator/worker-run.js +4 -1
  94. package/dist/operator/worker-run.js.map +1 -1
  95. package/dist/operator/workorder-consumer.d.ts +7 -0
  96. package/dist/operator/workorder-consumer.d.ts.map +1 -1
  97. package/dist/operator/workorder-consumer.js +30 -2
  98. package/dist/operator/workorder-consumer.js.map +1 -1
  99. package/dist/operator/workorder-publishers.d.ts +2 -0
  100. package/dist/operator/workorder-publishers.d.ts.map +1 -1
  101. package/dist/operator/workorder-publishers.js +12 -0
  102. package/dist/operator/workorder-publishers.js.map +1 -1
  103. package/package.json +2 -2
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_ISSUE_ERROR_CHARS = void 0;
4
+ exports.ensureOperationalIssuesTable = ensureOperationalIssuesTable;
5
+ exports.redactIssueError = redactIssueError;
6
+ exports.issueDedupeKey = issueDedupeKey;
7
+ exports.recordOperationalIssue = recordOperationalIssue;
8
+ exports.listOpenOperationalIssues = listOpenOperationalIssues;
9
+ exports.getOperationalIssue = getOperationalIssue;
10
+ exports.setOperationalIssueStatus = setOperationalIssueStatus;
11
+ exports.closeOperationalIssue = closeOperationalIssue;
12
+ /**
13
+ * Operational issues: the system's own failures as first-class evidence.
14
+ *
15
+ * Every place a failure already passes through (gateway tool failure, envelope scope
16
+ * mismatch, dead owner-event batch, ledger stagnation) records one row here, aggregated
17
+ * by (surface, signature). Every packet carries the open rows, so the agent sees what is
18
+ * broken before it judges anything; the daily self-check turn triages them.
19
+ *
20
+ * Stored error text passes the secret scan first and FAILS CLOSED: a non-clean scan stores
21
+ * no original characters. This table is read into every prompt, which makes it a new place
22
+ * for credentials to land.
23
+ *
24
+ * Table: awareness_operational_issues in the mama-core database (migration 066 creates it
25
+ * on a fresh install; an installed table without `occurrences` gets the column here).
26
+ */
27
+ const node_crypto_1 = require("node:crypto");
28
+ const secret_filter_js_1 = require("../memory/secret-filter.js");
29
+ const SURFACES = new Set([
30
+ 'gateway',
31
+ 'envelope',
32
+ 'inbox',
33
+ 'ledger',
34
+ 'budget',
35
+ 'delivery',
36
+ ]);
37
+ const SEVERITIES = new Set(['info', 'warn', 'error']);
38
+ const SEVERITY_RANK = { error: 0, warn: 1, info: 2 };
39
+ exports.MAX_ISSUE_ERROR_CHARS = 2_000;
40
+ const MAX_SIGNATURE_CHARS = 120;
41
+ const TABLE_DDL = `
42
+ CREATE TABLE IF NOT EXISTS awareness_operational_issues (
43
+ issue_id TEXT PRIMARY KEY,
44
+ dedupe_key TEXT UNIQUE NOT NULL,
45
+ surface TEXT NOT NULL,
46
+ severity TEXT NOT NULL,
47
+ status TEXT NOT NULL,
48
+ source_delta_id TEXT,
49
+ first_seen_at INTEGER NOT NULL CHECK (first_seen_at >= 0),
50
+ last_seen_at INTEGER NOT NULL CHECK (last_seen_at >= first_seen_at),
51
+ next_retry_at INTEGER,
52
+ last_error TEXT,
53
+ owner_agent TEXT,
54
+ occurrences INTEGER NOT NULL DEFAULT 1
55
+ )`;
56
+ /** Idempotent: creates the table on a bare DB, adds `occurrences` to an installed one. */
57
+ function ensureOperationalIssuesTable(db) {
58
+ db.prepare(TABLE_DDL).run();
59
+ const columns = db.prepare('PRAGMA table_info(awareness_operational_issues)').all();
60
+ if (!columns.some((column) => column.name === 'occurrences')) {
61
+ db.prepare('ALTER TABLE awareness_operational_issues ADD COLUMN occurrences INTEGER NOT NULL DEFAULT 1').run();
62
+ }
63
+ db.prepare(`CREATE INDEX IF NOT EXISTS idx_awareness_operational_issues_status_seen
64
+ ON awareness_operational_issues(status, last_seen_at DESC)`).run();
65
+ }
66
+ /** Redaction gate, fail closed: a non-clean scan stores none of the original characters. */
67
+ function redactIssueError(raw) {
68
+ const scan = (0, secret_filter_js_1.scanForSecrets)(raw);
69
+ if (!scan.clean) {
70
+ return `[redacted: ${scan.matches.join(',')}]`;
71
+ }
72
+ return raw.replace(/\s+/g, ' ').trim().slice(0, exports.MAX_ISSUE_ERROR_CHARS);
73
+ }
74
+ function digest(value) {
75
+ return `sha256:${(0, node_crypto_1.createHash)('sha256').update(value).digest('hex').slice(0, 24)}`;
76
+ }
77
+ function issueDedupeKey(surface, signature) {
78
+ return (0, node_crypto_1.createHash)('sha256').update(`${surface}\0${signature}`).digest('hex');
79
+ }
80
+ function recordOperationalIssue(db, input) {
81
+ if (!SURFACES.has(input.surface)) {
82
+ throw new Error(`operational issue: unknown surface ${String(input.surface)}`);
83
+ }
84
+ if (!SEVERITIES.has(input.severity)) {
85
+ throw new Error(`operational issue: unknown severity ${String(input.severity)}`);
86
+ }
87
+ const signature = input.signature.replace(/\s+/g, ' ').trim().slice(0, MAX_SIGNATURE_CHARS);
88
+ if (!signature) {
89
+ throw new Error('operational issue: signature is required');
90
+ }
91
+ const now = input.nowMs ?? Date.now();
92
+ const dedupeKey = issueDedupeKey(input.surface, signature);
93
+ const lastError = redactIssueError(input.error);
94
+ const sourceRef = input.sourceRef ? digest(input.sourceRef) : null;
95
+ const existing = db
96
+ .prepare(`SELECT issue_id, occurrences, status FROM awareness_operational_issues WHERE dedupe_key = ?`)
97
+ .all(dedupeKey);
98
+ if (existing.length > 0) {
99
+ const row = existing[0];
100
+ // A closed issue that recurs reopens: closure was a claim about the signature going quiet.
101
+ db.prepare(`UPDATE awareness_operational_issues
102
+ SET last_seen_at = MAX(last_seen_at, ?), occurrences = occurrences + 1,
103
+ last_error = ?, severity = ?, source_delta_id = COALESCE(?, source_delta_id),
104
+ owner_agent = COALESCE(?, owner_agent),
105
+ status = CASE WHEN status = 'closed' THEN 'open' ELSE status END
106
+ WHERE dedupe_key = ?`).run(now, `${signature} | ${lastError}`, input.severity, sourceRef, input.ownerAgent ?? null, dedupeKey);
107
+ return { issueId: row.issue_id, occurrences: row.occurrences + 1 };
108
+ }
109
+ const issueId = `iss_${dedupeKey.slice(0, 16)}`;
110
+ db.prepare(`INSERT INTO awareness_operational_issues
111
+ (issue_id, dedupe_key, surface, severity, status, source_delta_id, first_seen_at,
112
+ last_seen_at, next_retry_at, last_error, owner_agent, occurrences)
113
+ VALUES (?, ?, ?, ?, 'open', ?, ?, ?, NULL, ?, ?, 1)`).run(issueId, dedupeKey, input.surface, input.severity, sourceRef, now, now, `${signature} | ${lastError}`, input.ownerAgent ?? null);
114
+ return { issueId, occurrences: 1 };
115
+ }
116
+ function rowToIssue(row) {
117
+ const stored = typeof row.last_error === 'string' ? row.last_error : '';
118
+ const separator = stored.indexOf(' | ');
119
+ return {
120
+ issueId: String(row.issue_id),
121
+ surface: String(row.surface),
122
+ severity: String(row.severity),
123
+ status: String(row.status),
124
+ signature: separator > 0 ? stored.slice(0, separator) : stored,
125
+ lastError: separator > 0 ? stored.slice(separator + 3) : stored || null,
126
+ occurrences: Number(row.occurrences ?? 1),
127
+ firstSeenAt: Number(row.first_seen_at),
128
+ lastSeenAt: Number(row.last_seen_at),
129
+ };
130
+ }
131
+ /**
132
+ * Open issues: error before warn before info, then most recent, capped - ordered in SQL so an
133
+ * old error is never hidden behind newer info rows. `minSeverity` lets packets and the
134
+ * self-check turn skip designed refusals (info) while the table keeps counting them.
135
+ */
136
+ function listOpenOperationalIssues(db, limit = 20, minSeverity = 'info') {
137
+ const maxRank = SEVERITY_RANK[minSeverity] ?? 2;
138
+ const rows = db
139
+ .prepare(`SELECT * FROM awareness_operational_issues
140
+ WHERE status <> 'closed'
141
+ AND (CASE severity WHEN 'error' THEN 0 WHEN 'warn' THEN 1 ELSE 2 END) <= ?
142
+ ORDER BY (CASE severity WHEN 'error' THEN 0 WHEN 'warn' THEN 1 ELSE 2 END) ASC,
143
+ last_seen_at DESC
144
+ LIMIT ?`)
145
+ .all(maxRank, Math.min(Math.max(limit, 1), 200));
146
+ return rows.map(rowToIssue);
147
+ }
148
+ /** One issue by id, or null; the repair path checks existence before writing a bundle. */
149
+ function getOperationalIssue(db, issueId) {
150
+ const rows = db
151
+ .prepare(`SELECT * FROM awareness_operational_issues WHERE issue_id = ?`)
152
+ .all(issueId);
153
+ return rows.length > 0 ? rowToIssue(rows[0]) : null;
154
+ }
155
+ function setOperationalIssueStatus(db, issueId, status) {
156
+ const result = db
157
+ .prepare(`UPDATE awareness_operational_issues SET status = ? WHERE issue_id = ?`)
158
+ .run(status, issueId);
159
+ if (!result || result.changes !== 1) {
160
+ throw new Error(`operational issue not found: ${issueId}`);
161
+ }
162
+ }
163
+ /** Closing is a claim that the signature went quiet; an unknown id is an error, not a no-op. */
164
+ function closeOperationalIssue(db, issueId, reason) {
165
+ if (!reason.trim()) {
166
+ throw new Error('operational issue: a close reason is required');
167
+ }
168
+ setOperationalIssueStatus(db, issueId, 'closed');
169
+ }
170
+ //# sourceMappingURL=operational-issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operational-issues.js","sourceRoot":"","sources":["../../src/observability/operational-issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type ExportFormat = 'csv' | 'md';
2
+ export interface ExportFileInput {
3
+ format: ExportFormat;
4
+ name: string;
5
+ columns?: string[];
6
+ rows?: Array<Record<string, string | number | null>>;
7
+ content?: string;
8
+ }
9
+ export interface ExportFileResult {
10
+ path: string;
11
+ bytes: number;
12
+ sha256: string;
13
+ }
14
+ export declare const EXPORT_DIR_NAME = "exports";
15
+ /** The one place the exports root is computed. Mirrors owner-event-effects.ts (MAMA_WORKSPACE). */
16
+ export declare function resolveExportRoot(env?: NodeJS.ProcessEnv): string;
17
+ /** Safe basename: ascii letters, digits and dashes; everything else (including path parts) collapses. */
18
+ export declare function slugExportName(name: string): string;
19
+ export declare function renderCsv(rows: Array<Record<string, string | number | null>>, columns?: string[]): string;
20
+ /** Pure apart from the write. Never overwrites; never escapes the root. */
21
+ export declare function exportFile(input: ExportFileInput, root: string, nowMs?: number): Promise<ExportFileResult>;
22
+ //# sourceMappingURL=file-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-export.d.ts","sourceRoot":"","sources":["../../src/operator/file-export.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,eAAe,YAAY,CAAC;AAIzC,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG9E;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnD;AAiBD,wBAAgB,SAAS,CACvB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,EACnD,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,MAAM,CAQR;AASD,2EAA2E;AAC3E,wBAAsB,UAAU,CAC9B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAmB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA2C3B"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EXPORT_DIR_NAME = void 0;
4
+ exports.resolveExportRoot = resolveExportRoot;
5
+ exports.slugExportName = slugExportName;
6
+ exports.renderCsv = renderCsv;
7
+ exports.exportFile = exportFile;
8
+ /**
9
+ * file_export: the smallest path from "make me a file" to a file the owner can receive.
10
+ *
11
+ * Writes only under the private workspace exports root (the same root telegram_send and
12
+ * drive_upload accept through resolvePrivateWorkspaceFile), never overwrites (wx flag),
13
+ * never escapes the root, and returns the bytes and sha256 the executor records as an
14
+ * effect. csv and md ship first: both need no dependency and both open where the owner
15
+ * works. Formula-leading cells are neutralised because the owner opens the csv in Excel.
16
+ */
17
+ const node_crypto_1 = require("node:crypto");
18
+ const node_fs_1 = require("node:fs");
19
+ const node_os_1 = require("node:os");
20
+ const node_path_1 = require("node:path");
21
+ exports.EXPORT_DIR_NAME = 'exports';
22
+ const MAX_ROWS = 5_000;
23
+ const MAX_BYTES = 8 * 1024 * 1024;
24
+ /** The one place the exports root is computed. Mirrors owner-event-effects.ts (MAMA_WORKSPACE). */
25
+ function resolveExportRoot(env = process.env) {
26
+ const workspace = (0, node_path_1.resolve)(env.MAMA_WORKSPACE || (0, node_path_1.join)((0, node_os_1.homedir)(), '.mama', 'workspace'));
27
+ return (0, node_path_1.join)(workspace, exports.EXPORT_DIR_NAME);
28
+ }
29
+ /** Safe basename: ascii letters, digits and dashes; everything else (including path parts) collapses. */
30
+ function slugExportName(name) {
31
+ const slug = name
32
+ .normalize('NFKD')
33
+ .replace(/[^\x20-\x7e]/g, '')
34
+ .toLowerCase()
35
+ .replace(/[^a-z0-9]+/g, '-')
36
+ .replace(/^-+|-+$/g, '')
37
+ .slice(0, 60);
38
+ return slug || 'export';
39
+ }
40
+ function csvCell(value) {
41
+ if (value === null || value === undefined) {
42
+ return '';
43
+ }
44
+ let text = String(value);
45
+ // A leading =, +, -, @ (or a tab/CR) is a formula to a spreadsheet: prefix an apostrophe.
46
+ if (/^[=+\-@\t\r]/.test(text)) {
47
+ text = `'${text}`;
48
+ }
49
+ if (/[",\r\n]/.test(text)) {
50
+ return `"${text.replace(/"/g, '""')}"`;
51
+ }
52
+ return text;
53
+ }
54
+ function renderCsv(rows, columns) {
55
+ const header = columns && columns.length > 0 ? columns : [...new Set(rows.flatMap((row) => Object.keys(row)))];
56
+ const lines = [header.map(csvCell).join(',')];
57
+ for (const row of rows) {
58
+ lines.push(header.map((column) => csvCell(row[column] ?? null)).join(','));
59
+ }
60
+ return `${lines.join('\r\n')}\r\n`;
61
+ }
62
+ function timestampSuffix(nowMs) {
63
+ return new Date(nowMs)
64
+ .toISOString()
65
+ .replace(/[-:]/g, '')
66
+ .replace(/\.\d{3}Z$/, 'Z');
67
+ }
68
+ /** Pure apart from the write. Never overwrites; never escapes the root. */
69
+ async function exportFile(input, root, nowMs = Date.now()) {
70
+ if (input.format !== 'csv' && input.format !== 'md') {
71
+ throw new Error(`file_export: unsupported format ${String(input.format)}`);
72
+ }
73
+ let body;
74
+ if (input.format === 'csv') {
75
+ if (!Array.isArray(input.rows)) {
76
+ throw new Error('file_export: csv requires rows');
77
+ }
78
+ if (input.rows.length > MAX_ROWS) {
79
+ throw new Error(`file_export: csv rows exceed ${MAX_ROWS}`);
80
+ }
81
+ body = renderCsv(input.rows, input.columns);
82
+ }
83
+ else {
84
+ if (typeof input.content !== 'string' || input.content.trim() === '') {
85
+ throw new Error('file_export: md requires content');
86
+ }
87
+ body = input.content.endsWith('\n') ? input.content : `${input.content}\n`;
88
+ }
89
+ const bytes = Buffer.byteLength(body, 'utf-8');
90
+ if (bytes > MAX_BYTES) {
91
+ throw new Error(`file_export: ${bytes} bytes exceeds ${MAX_BYTES}`);
92
+ }
93
+ const realRoot = (0, node_path_1.resolve)(root);
94
+ (0, node_fs_1.mkdirSync)(realRoot, { recursive: true });
95
+ const base = `${slugExportName(input.name)}-${timestampSuffix(nowMs)}`;
96
+ for (let attempt = 0; attempt < 100; attempt += 1) {
97
+ const fileName = `${base}${attempt === 0 ? '' : `-${attempt}`}.${input.format}`;
98
+ const path = (0, node_path_1.resolve)(realRoot, fileName);
99
+ if (path !== realRoot && !path.startsWith(`${realRoot}${node_path_1.sep}`)) {
100
+ throw new Error(`file_export: refusing to write outside ${realRoot}`);
101
+ }
102
+ try {
103
+ (0, node_fs_1.writeFileSync)(path, body, { encoding: 'utf-8', flag: 'wx' });
104
+ }
105
+ catch (error) {
106
+ if (error.code === 'EEXIST') {
107
+ continue; // never overwrite: same second, same name -> counter
108
+ }
109
+ throw error;
110
+ }
111
+ return { path, bytes, sha256: (0, node_crypto_1.createHash)('sha256').update(body).digest('hex') };
112
+ }
113
+ throw new Error('file_export: could not find a free file name');
114
+ }
115
+ //# sourceMappingURL=file-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-export.js","sourceRoot":"","sources":["../../src/operator/file-export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Owner policy and lessons, injected into every turn.
3
+ *
4
+ * Conversation changes operations only if what the owner said reaches the next turn.
5
+ * Two kinds of memory rows do that: `policy:` rows (rules in force, rendered
6
+ * unconditionally for the turn's scope) and `lesson:` rows (corrections, ranked by the
7
+ * turn's query, bounded). Both are OWNER-authored data inside a trusted block, so every
8
+ * rendered value is markup-escaped and every line is budgeted before assembly: a stored
9
+ * string can never close the block or author a tag, and a closing tag is never truncated.
10
+ */
11
+ import type { MemoryScopeRef, MemoryTruthRow } from '@jungjaehoon/mama-core/memory/types';
12
+ export interface LearningContextInput {
13
+ /** Same scope list the turn's envelope uses; build it with deriveMemoryScopes. */
14
+ scopes: MemoryScopeRef[];
15
+ /** Kept for the audit line; ranking is by recency (see buildLearningContext). */
16
+ query: string;
17
+ /** Bounded reads. `query: ''` returns everything in scope. */
18
+ readClaims: (input: {
19
+ scopes: MemoryScopeRef[];
20
+ query: string;
21
+ }) => Promise<MemoryTruthRow[]>;
22
+ limits?: {
23
+ maxLessons?: number;
24
+ maxSummaryChars?: number;
25
+ maxTotalChars?: number;
26
+ };
27
+ }
28
+ export interface LearningContext {
29
+ /** Ready-to-append prompt text. Empty string when nothing qualifies. */
30
+ promptBlock: string;
31
+ policyIds: string[];
32
+ lessonIds: string[];
33
+ /** For the daemon.log prompt-audit line the acceptance test reads. */
34
+ audit: {
35
+ policyCount: number;
36
+ lessonCount: number;
37
+ renderedChars: number;
38
+ };
39
+ }
40
+ export declare const POLICY_TOPIC_PREFIX = "policy:";
41
+ export declare const LESSON_TOPIC_PREFIX = "lesson:";
42
+ /** Topics the host owns: only the turn observer writes them (gateway refuses the agent). */
43
+ export declare function isLearningTopic(topic: unknown): boolean;
44
+ /** Owner text is data inside a trusted block: it must not be able to author markup. */
45
+ export declare function escapePromptMarkup(text: string): string;
46
+ export declare function buildLearningContext(input: LearningContextInput): Promise<LearningContext>;
47
+ /** One prompt-audit line per turn; the installed acceptance test greps it. */
48
+ export declare function formatLearningAuditLine(turn: string, channelScopeId: string | null, context: LearningContext): string;
49
+ //# sourceMappingURL=learning-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-context.d.ts","sourceRoot":"","sources":["../../src/operator/learning-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1F,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,UAAU,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9F,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpF;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,sEAAsE;IACtE,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5E;AAED,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAC7C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMvD;AAMD,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAuFD,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkDhG;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,OAAO,EAAE,eAAe,GACvB,MAAM,CAER"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LESSON_TOPIC_PREFIX = exports.POLICY_TOPIC_PREFIX = void 0;
4
+ exports.isLearningTopic = isLearningTopic;
5
+ exports.escapePromptMarkup = escapePromptMarkup;
6
+ exports.buildLearningContext = buildLearningContext;
7
+ exports.formatLearningAuditLine = formatLearningAuditLine;
8
+ exports.POLICY_TOPIC_PREFIX = 'policy:';
9
+ exports.LESSON_TOPIC_PREFIX = 'lesson:';
10
+ /** Topics the host owns: only the turn observer writes them (gateway refuses the agent). */
11
+ function isLearningTopic(topic) {
12
+ return (typeof topic === 'string' &&
13
+ (topic.trimStart().toLowerCase().startsWith(exports.POLICY_TOPIC_PREFIX) ||
14
+ topic.trimStart().toLowerCase().startsWith(exports.LESSON_TOPIC_PREFIX)));
15
+ }
16
+ const DEFAULT_LIMITS = { maxLessons: 3, maxSummaryChars: 240, maxTotalChars: 2400 };
17
+ const POLICY_INSTRUCTION = 'Owner policy, in force. Apply it. The host still enforces revisions, receipts and destinations.';
18
+ const LESSON_INSTRUCTION = 'Use as lessons, not facts; verify with the packet.';
19
+ /** Owner text is data inside a trusted block: it must not be able to author markup. */
20
+ function escapePromptMarkup(text) {
21
+ return text
22
+ .replace(/&(?!amp;|lt;|gt;|quot;|apos;)/g, '&amp;')
23
+ .replace(/</g, '&lt;')
24
+ .replace(/>/g, '&gt;');
25
+ }
26
+ /** Ported gate: never render a half-formed row. */
27
+ function renderable(row) {
28
+ if (typeof row.effective_summary !== 'string' || row.effective_summary.trim() === '') {
29
+ return false;
30
+ }
31
+ if (!Array.isArray(row.scope_refs)) {
32
+ return false;
33
+ }
34
+ if (!row.scope_refs.some((scope) => scope.kind === 'project')) {
35
+ return false;
36
+ }
37
+ return typeof row.updated_at === 'number' || typeof row.created_at === 'number';
38
+ }
39
+ /**
40
+ * A turn may carry more than one channel scope (a board reconcile carries the synthetic
41
+ * worker channel AND the channel it judges); a row matches when it names ANY of them.
42
+ */
43
+ function hasChannelScope(row, turnChannels) {
44
+ return row.scope_refs.some((scope) => scope.kind === 'channel' && turnChannels.has(scope.id));
45
+ }
46
+ /** A policy applies when it names no channel (project- or global-wide) or one of this turn's. */
47
+ function policyScopeMatches(row, turnChannels) {
48
+ const channels = row.scope_refs.filter((scope) => scope.kind === 'channel');
49
+ if (channels.length === 0) {
50
+ return true;
51
+ }
52
+ return hasChannelScope(row, turnChannels);
53
+ }
54
+ function recency(row) {
55
+ return row.updated_at ?? row.created_at ?? 0;
56
+ }
57
+ /** One line per row: a newline in stored text could forge a section heading, so it is collapsed. */
58
+ function renderLine(row, prefix, maxSummaryChars) {
59
+ const name = escapePromptMarkup(row.topic.slice(prefix.length).replace(/\s+/g, ' ').trim() || 'untitled');
60
+ const summary = escapePromptMarkup(row.effective_summary.replace(/\s+/g, ' ').trim().slice(0, maxSummaryChars));
61
+ return `- ${name}: ${summary}`;
62
+ }
63
+ /**
64
+ * Budget each line against the remaining chars and drop whole lines; never slice the
65
+ * assembled string. Returns the block and the rows that made it in.
66
+ */
67
+ function renderBlock(tag, instruction, rows, prefix, maxSummaryChars, budget) {
68
+ if (rows.length === 0) {
69
+ return { block: '', rendered: [] };
70
+ }
71
+ const open = `<${tag}>`;
72
+ const close = `</${tag}>`;
73
+ const frame = open.length + 1 + instruction.length + 1 + close.length;
74
+ if (frame > budget) {
75
+ return { block: '', rendered: [] };
76
+ }
77
+ let used = frame;
78
+ const lines = [];
79
+ const rendered = [];
80
+ for (const row of rows) {
81
+ const line = renderLine(row, prefix, maxSummaryChars);
82
+ if (used + line.length + 1 > budget) {
83
+ continue;
84
+ }
85
+ used += line.length + 1;
86
+ lines.push(line);
87
+ rendered.push(row);
88
+ }
89
+ if (lines.length === 0) {
90
+ return { block: '', rendered: [] };
91
+ }
92
+ return { block: [open, instruction, ...lines, close].join('\n'), rendered };
93
+ }
94
+ async function buildLearningContext(input) {
95
+ const limits = { ...DEFAULT_LIMITS, ...(input.limits ?? {}) };
96
+ const turnChannels = new Set(input.scopes.filter((scope) => scope.kind === 'channel').map((scope) => scope.id));
97
+ // ONE read with an empty query: it returns every active row in scope, which is a superset
98
+ // of what a ranked lesson read would return, and queryRelevantTruth has no LIMIT - a second
99
+ // scan of the same rows bought nothing. Lessons are channel-bound and few; recency ranks them.
100
+ const rows = await input.readClaims({ scopes: input.scopes, query: '' });
101
+ const policies = rows
102
+ .filter((row) => row.topic.startsWith(exports.POLICY_TOPIC_PREFIX) && renderable(row))
103
+ .filter((row) => policyScopeMatches(row, turnChannels))
104
+ .sort((a, b) => recency(b) - recency(a));
105
+ const lessons = rows
106
+ .filter((row) => row.topic.startsWith(exports.LESSON_TOPIC_PREFIX) && renderable(row))
107
+ .filter((row) => hasChannelScope(row, turnChannels))
108
+ .sort((a, b) => recency(b) - recency(a))
109
+ .slice(0, limits.maxLessons);
110
+ const policyBlock = renderBlock('policy', POLICY_INSTRUCTION, policies, exports.POLICY_TOPIC_PREFIX, limits.maxSummaryChars, limits.maxTotalChars);
111
+ const remaining = limits.maxTotalChars - (policyBlock.block ? policyBlock.block.length + 2 : 0);
112
+ const lessonBlock = renderBlock('lessons', LESSON_INSTRUCTION, lessons, exports.LESSON_TOPIC_PREFIX, limits.maxSummaryChars, remaining);
113
+ const promptBlock = [policyBlock.block, lessonBlock.block].filter(Boolean).join('\n\n');
114
+ return {
115
+ promptBlock,
116
+ policyIds: policyBlock.rendered.map((row) => row.memory_id),
117
+ lessonIds: lessonBlock.rendered.map((row) => row.memory_id),
118
+ audit: {
119
+ policyCount: policyBlock.rendered.length,
120
+ lessonCount: lessonBlock.rendered.length,
121
+ renderedChars: promptBlock.length,
122
+ },
123
+ };
124
+ }
125
+ /** One prompt-audit line per turn; the installed acceptance test greps it. */
126
+ function formatLearningAuditLine(turn, channelScopeId, context) {
127
+ return `[learning] turn=${turn} channel=${channelScopeId ?? '-'} policyIds=[${context.policyIds.join(',')}] lessonIds=[${context.lessonIds.join(',')}] chars=${context.audit.renderedChars}`;
128
+ }
129
+ //# sourceMappingURL=learning-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-context.js","sourceRoot":"","sources":["../../src/operator/learning-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface LearningMarkerConfig {
2
+ durableRule: string[];
3
+ correction: string[];
4
+ oneOffVeto: string[];
5
+ topicNouns: Record<string, string[]>;
6
+ }
7
+ export declare const DEFAULT_LEARNING_MARKERS: LearningMarkerConfig;
8
+ export interface DurableInstruction {
9
+ kind: 'policy' | 'lesson' | 'none';
10
+ topicNoun?: string;
11
+ matchedMarkers: string[];
12
+ /** Why it was or was not classified; goes into the audit log. */
13
+ reason: string;
14
+ }
15
+ export declare function learningMarkersPath(env?: NodeJS.ProcessEnv): string;
16
+ /** Defaults merged with the owner's overrides; overrides ADD to a list, never replace it. */
17
+ export declare function loadLearningMarkers(env?: NodeJS.ProcessEnv): LearningMarkerConfig;
18
+ export declare function detectDurableInstruction(text: string, cfg?: LearningMarkerConfig): DurableInstruction;
19
+ //# sourceMappingURL=learning-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-markers.d.ts","sourceRoot":"","sources":["../../src/operator/learning-markers.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACtC;AAED,eAAO,MAAM,wBAAwB,EAAE,oBAUtC,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEhF;AAUD,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,oBAAoB,CA2C9F;AAyBD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,oBAA+C,GACnD,kBAAkB,CA0CpB"}