@almadar/agent 1.6.1 → 1.6.2

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.
@@ -0,0 +1,675 @@
1
+ import { readFile, writeFile, mkdir, access } from 'fs/promises';
2
+ import { basename, join } from 'path';
3
+ import { execFile } from 'child_process';
4
+
5
+ // src/workspace/types.ts
6
+ var WORKSPACE_LAYOUT = {
7
+ /** Root directory for Almadar workspace state. */
8
+ ALMADAR_DIR: ".almadar",
9
+ /** User preferences and learned patterns. */
10
+ USER_MEMORY: ".almadar/user.orb",
11
+ /** Project-level domain knowledge. */
12
+ PROJECT_MEMORY: ".almadar/project.orb",
13
+ /** The generation artifact (shared memory for all agents). */
14
+ SCHEMA: ".almadar/schema.orb",
15
+ /** Individual orbital files (one per subagent). */
16
+ ORBITALS_DIR: ".almadar/orbitals"
17
+ };
18
+
19
+ // src/workspace/sink-manager.ts
20
+ var SinkManager = class {
21
+ constructor() {
22
+ this.sinks = [];
23
+ }
24
+ /** Register a sink to receive file write notifications. */
25
+ register(sink) {
26
+ this.sinks.push(sink);
27
+ }
28
+ /** Get registered sink names (for diagnostics). */
29
+ get registeredSinks() {
30
+ return this.sinks.map((s) => s.name);
31
+ }
32
+ /**
33
+ * Notify all sinks that a file was written.
34
+ * Returns results from each sink — failures in one don't affect others.
35
+ */
36
+ async notifyFileWritten(path, content, meta) {
37
+ if (this.sinks.length === 0) return [];
38
+ const results = await Promise.allSettled(
39
+ this.sinks.map((sink) => sink.onFileWritten(path, content, meta))
40
+ );
41
+ return results.map((result, i) => ({
42
+ sinkName: this.sinks[i].name,
43
+ success: result.status === "fulfilled",
44
+ error: result.status === "rejected" ? toError(result.reason) : void 0
45
+ }));
46
+ }
47
+ /**
48
+ * Notify all sinks that the session has ended.
49
+ * Returns results from each sink — failures in one don't affect others.
50
+ */
51
+ async notifySessionEnd(sessionId) {
52
+ if (this.sinks.length === 0) return [];
53
+ const results = await Promise.allSettled(
54
+ this.sinks.map((sink) => sink.onSessionEnd(sessionId))
55
+ );
56
+ return results.map((result, i) => ({
57
+ sinkName: this.sinks[i].name,
58
+ success: result.status === "fulfilled",
59
+ error: result.status === "rejected" ? toError(result.reason) : void 0
60
+ }));
61
+ }
62
+ };
63
+ function toError(reason) {
64
+ if (reason instanceof Error) return reason;
65
+ return new Error(String(reason));
66
+ }
67
+ var GitClient = class {
68
+ constructor(cwd) {
69
+ this.cwd = cwd;
70
+ }
71
+ /** Check if git is available on the system. */
72
+ static async isAvailable() {
73
+ try {
74
+ await execGit(["--version"], "/tmp");
75
+ return true;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ /** Check if the workspace is already a git repository. */
81
+ async isRepo() {
82
+ try {
83
+ await this.exec(["rev-parse", "--is-inside-work-tree"]);
84
+ return true;
85
+ } catch {
86
+ return false;
87
+ }
88
+ }
89
+ /** Initialize a new git repository. No-op if already initialized. */
90
+ async init() {
91
+ if (await this.isRepo()) return;
92
+ await this.exec(["init"]);
93
+ await this.exec(["config", "user.email", "agent@almadar.io"]);
94
+ await this.exec(["config", "user.name", "Almadar Agent"]);
95
+ }
96
+ /** Stage files for commit. */
97
+ async add(paths) {
98
+ if (paths.length === 0) return;
99
+ await this.exec(["add", ...paths]);
100
+ }
101
+ /** Stage all changes (equivalent to git add -A). */
102
+ async addAll() {
103
+ await this.exec(["add", "-A"]);
104
+ }
105
+ /**
106
+ * Create a commit with the given message.
107
+ * Returns the commit hash, or null if there was nothing to commit.
108
+ */
109
+ async commit(message) {
110
+ try {
111
+ const output = await this.exec(["commit", "-m", message, "--allow-empty-message"]);
112
+ const match = output.match(/\[[\w/.-]+ ([a-f0-9]+)\]/);
113
+ return match ? match[1] : null;
114
+ } catch (err) {
115
+ if (err instanceof Error && err.message.includes("nothing to commit")) {
116
+ return null;
117
+ }
118
+ throw err;
119
+ }
120
+ }
121
+ /** Create an annotated tag. */
122
+ async tag(name, message) {
123
+ const args = ["tag"];
124
+ if (message) {
125
+ args.push("-a", name, "-m", message);
126
+ } else {
127
+ args.push(name);
128
+ }
129
+ await this.exec(args);
130
+ }
131
+ /** Get recent commits. */
132
+ async log(limit = 10) {
133
+ try {
134
+ const output = await this.exec([
135
+ "log",
136
+ `--max-count=${limit}`,
137
+ "--format=%H|%s|%aI|%an"
138
+ ]);
139
+ return output.trim().split("\n").filter(Boolean).map((line) => {
140
+ const [hash, message, date, author] = line.split("|");
141
+ return { hash, message, date, author };
142
+ });
143
+ } catch {
144
+ return [];
145
+ }
146
+ }
147
+ /** Get workspace status. */
148
+ async status() {
149
+ const output = await this.exec(["status", "--porcelain"]);
150
+ const lines = output.trim().split("\n").filter(Boolean);
151
+ const staged = [];
152
+ const modified = [];
153
+ const untracked = [];
154
+ for (const line of lines) {
155
+ const indexStatus = line[0];
156
+ const workTreeStatus = line[1];
157
+ const file = line.slice(3);
158
+ if (indexStatus === "?" && workTreeStatus === "?") {
159
+ untracked.push(file);
160
+ } else if (indexStatus !== " " && indexStatus !== "?") {
161
+ staged.push(file);
162
+ } else if (workTreeStatus !== " ") {
163
+ modified.push(file);
164
+ }
165
+ }
166
+ return {
167
+ clean: lines.length === 0,
168
+ staged,
169
+ modified,
170
+ untracked
171
+ };
172
+ }
173
+ /** Get diff output between two references. */
174
+ async diff(from, to) {
175
+ const args = ["diff"];
176
+ if (from) args.push(from);
177
+ if (to) args.push(to);
178
+ return this.exec(args);
179
+ }
180
+ exec(args) {
181
+ return execGit(args, this.cwd);
182
+ }
183
+ };
184
+ function execGit(args, cwd) {
185
+ return new Promise((resolve, reject) => {
186
+ execFile("git", args, { cwd, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
187
+ if (err) {
188
+ const message = stderr?.trim() || stdout?.trim() || err.message;
189
+ reject(new Error(`git ${args[0]}: ${message}`));
190
+ return;
191
+ }
192
+ resolve(stdout);
193
+ });
194
+ });
195
+ }
196
+ var GitSink = class {
197
+ constructor(workspaceRoot) {
198
+ this.name = "git";
199
+ this.commitQueue = Promise.resolve();
200
+ this.available = null;
201
+ this.client = new GitClient(workspaceRoot);
202
+ }
203
+ /** Initialize the git repo. Must be called before onFileWritten. */
204
+ async initialize() {
205
+ this.available = await GitClient.isAvailable();
206
+ if (!this.available) {
207
+ console.warn("[GitSink] git not available \u2014 commits will be skipped");
208
+ return;
209
+ }
210
+ await this.client.init();
211
+ }
212
+ async onFileWritten(path, _content, meta) {
213
+ if (!this.available) return;
214
+ this.commitQueue = this.commitQueue.then(async () => {
215
+ const message = formatCommitMessage(path, meta);
216
+ await this.client.add([path]);
217
+ await this.client.commit(message);
218
+ });
219
+ await this.commitQueue;
220
+ }
221
+ async onSessionEnd(sessionId) {
222
+ if (!this.available) return;
223
+ await this.commitQueue;
224
+ const status = await this.client.status();
225
+ if (!status.clean) {
226
+ await this.client.addAll();
227
+ await this.client.commit(`session-end: ${sessionId}`);
228
+ }
229
+ await this.client.tag(
230
+ `session/${sessionId}`,
231
+ `Session ${sessionId} complete`
232
+ );
233
+ }
234
+ };
235
+ function formatCommitMessage(path, meta) {
236
+ const filename = basename(path);
237
+ switch (meta.fileType) {
238
+ case "orbital":
239
+ return `add(${meta.orbitalName ?? filename}): orbital generated`;
240
+ case "schema":
241
+ return `update(schema): ${filename}`;
242
+ case "memory":
243
+ return `update(memory): ${filename}`;
244
+ case "domain":
245
+ return `add(domain): ${filename}`;
246
+ default:
247
+ return `update: ${filename}`;
248
+ }
249
+ }
250
+
251
+ // src/memory/memory-orbital.ts
252
+ var UserPreferenceEntity = {
253
+ name: "UserPreference",
254
+ persistence: "persistent",
255
+ fields: [
256
+ { name: "id", type: "string", required: true },
257
+ { name: "userId", type: "string", required: true },
258
+ { name: "namingConvention", type: "enum", values: ["PascalCase", "camelCase", "snake_case"], default: "PascalCase" },
259
+ { name: "validationStyle", type: "enum", values: ["strict", "minimal", "none"], default: "strict" },
260
+ { name: "preferredPatterns", type: "array", items: { name: "pattern", type: "string" }, default: [] },
261
+ { name: "commonEntities", type: "array", items: { name: "entity", type: "string" }, default: [] },
262
+ { name: "commonTraits", type: "array", items: { name: "trait", type: "string" }, default: [] },
263
+ { name: "learnedAt", type: "timestamp" },
264
+ { name: "confidence", type: "number", default: 0.5 }
265
+ ]
266
+ };
267
+ var ProjectContextEntity = {
268
+ name: "ProjectContext",
269
+ persistence: "persistent",
270
+ fields: [
271
+ { name: "id", type: "string", required: true },
272
+ { name: "appId", type: "string", required: true },
273
+ { name: "userId", type: "string", required: true },
274
+ { name: "projectName", type: "string" },
275
+ { name: "description", type: "string" },
276
+ { name: "existingEntities", type: "array", items: { name: "entity", type: "string" }, default: [] },
277
+ { name: "conventions", type: "array", items: { name: "convention", type: "string" }, default: [] },
278
+ { name: "domain", type: "enum", values: ["business", "ecommerce", "cms", "dashboard", "workflow"], default: "business" },
279
+ { name: "lastUpdatedAt", type: "timestamp", required: true }
280
+ ]
281
+ };
282
+
283
+ // src/workspace/templates.ts
284
+ function createUserOrbTemplate(userId) {
285
+ const entity = {
286
+ ...UserPreferenceEntity,
287
+ instances: [{
288
+ id: `pref-${userId}`,
289
+ userId,
290
+ namingConvention: "PascalCase",
291
+ validationStyle: "strict",
292
+ preferredPatterns: [],
293
+ commonEntities: [],
294
+ commonTraits: [],
295
+ confidence: 0
296
+ }]
297
+ };
298
+ return {
299
+ name: "UserMemory",
300
+ version: "1.0.0",
301
+ description: "User preferences and learned patterns",
302
+ orbitals: [{
303
+ name: "PreferenceTracking",
304
+ entity,
305
+ traits: [{
306
+ name: "Learning",
307
+ category: "interaction",
308
+ linkedEntity: "UserPreference",
309
+ stateMachine: {
310
+ states: [
311
+ { name: "Cold", isInitial: true },
312
+ { name: "Warming" },
313
+ { name: "Confident" }
314
+ ],
315
+ events: [
316
+ { key: "SESSION_COMPLETE", name: "Session Complete" },
317
+ { key: "RESET", name: "Reset" }
318
+ ],
319
+ transitions: [
320
+ {
321
+ from: "Cold",
322
+ to: "Warming",
323
+ event: "SESSION_COMPLETE",
324
+ effects: [["set", "@entity.confidence", ["min", 1, ["add", "@entity.confidence", 0.1]]]]
325
+ },
326
+ {
327
+ from: "Warming",
328
+ to: "Warming",
329
+ event: "SESSION_COMPLETE",
330
+ guard: ["<", "@entity.confidence", 0.8],
331
+ effects: [["set", "@entity.confidence", ["min", 1, ["add", "@entity.confidence", 0.1]]]]
332
+ },
333
+ {
334
+ from: "Warming",
335
+ to: "Confident",
336
+ event: "SESSION_COMPLETE",
337
+ guard: [">=", "@entity.confidence", 0.8]
338
+ },
339
+ {
340
+ from: "Confident",
341
+ to: "Cold",
342
+ event: "RESET",
343
+ effects: [["set", "@entity.confidence", 0]]
344
+ }
345
+ ]
346
+ }
347
+ }],
348
+ pages: []
349
+ }]
350
+ };
351
+ }
352
+ function createProjectOrbTemplate(projectName, appId) {
353
+ const entity = {
354
+ ...ProjectContextEntity,
355
+ instances: [{
356
+ id: appId ?? `project-${projectName}`,
357
+ appId: appId ?? "",
358
+ userId: "",
359
+ projectName,
360
+ description: "",
361
+ existingEntities: [],
362
+ conventions: [],
363
+ domain: "business",
364
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
365
+ }]
366
+ };
367
+ return {
368
+ name: "ProjectMemory",
369
+ version: "1.0.0",
370
+ description: `Domain knowledge for ${projectName}`,
371
+ orbitals: [{
372
+ name: "DomainKnowledge",
373
+ entity,
374
+ traits: [{
375
+ name: "Accumulating",
376
+ category: "interaction",
377
+ linkedEntity: "ProjectContext",
378
+ stateMachine: {
379
+ states: [
380
+ { name: "Empty", isInitial: true },
381
+ { name: "Growing" },
382
+ { name: "Mature" }
383
+ ],
384
+ events: [
385
+ { key: "ENTITY_DISCOVERED", name: "Entity Discovered" },
386
+ { key: "SESSION_COMPLETE", name: "Session Complete" }
387
+ ],
388
+ transitions: [
389
+ { from: "Empty", to: "Growing", event: "ENTITY_DISCOVERED" },
390
+ { from: "Growing", to: "Growing", event: "ENTITY_DISCOVERED" },
391
+ {
392
+ from: "Growing",
393
+ to: "Mature",
394
+ event: "SESSION_COMPLETE",
395
+ guard: [">=", "@entity.sessionCount", 5]
396
+ }
397
+ ]
398
+ }
399
+ }],
400
+ pages: []
401
+ }]
402
+ };
403
+ }
404
+ function createSchemaOrbTemplate(name) {
405
+ return {
406
+ name,
407
+ version: "1.0.0",
408
+ description: "",
409
+ orbitals: []
410
+ };
411
+ }
412
+ function serializeOrb(schema) {
413
+ return JSON.stringify(schema, null, 2);
414
+ }
415
+ function parseOrb(content) {
416
+ try {
417
+ return JSON.parse(content);
418
+ } catch {
419
+ return null;
420
+ }
421
+ }
422
+ async function readOrbInstances(filePath) {
423
+ try {
424
+ const content = await readFile(filePath, "utf-8");
425
+ const schema = JSON.parse(content);
426
+ const entity = schema.orbitals?.[0]?.entity;
427
+ if (!entity || typeof entity === "string") return [];
428
+ return entity.instances ?? [];
429
+ } catch {
430
+ return [];
431
+ }
432
+ }
433
+ async function readOrb(filePath) {
434
+ try {
435
+ const content = await readFile(filePath, "utf-8");
436
+ return JSON.parse(content);
437
+ } catch {
438
+ return null;
439
+ }
440
+ }
441
+ async function writeOrbInstances(filePath, instances) {
442
+ try {
443
+ const content = await readFile(filePath, "utf-8");
444
+ const schema = JSON.parse(content);
445
+ const entity = schema.orbitals?.[0]?.entity;
446
+ if (!entity || typeof entity === "string") return false;
447
+ entity.instances = instances;
448
+ await writeFile(filePath, JSON.stringify(schema, null, 2), "utf-8");
449
+ return true;
450
+ } catch {
451
+ return false;
452
+ }
453
+ }
454
+ async function writeOrb(filePath, schema) {
455
+ await writeFile(filePath, JSON.stringify(schema, null, 2), "utf-8");
456
+ }
457
+
458
+ // src/workspace/workspace-manager.ts
459
+ var WorkspaceManager = class {
460
+ constructor(config) {
461
+ this.gitSink = null;
462
+ this.initialized = false;
463
+ this.config = config;
464
+ this.sinkManager = new SinkManager();
465
+ if (config.sinks) {
466
+ for (const sink of config.sinks) {
467
+ this.sinkManager.register(sink);
468
+ }
469
+ }
470
+ }
471
+ /** Get the absolute path to a workspace-relative path. */
472
+ resolve(relativePath) {
473
+ return join(this.config.rootDir, relativePath);
474
+ }
475
+ /** Get the SinkManager for direct registration of additional sinks. */
476
+ get sinks() {
477
+ return this.sinkManager;
478
+ }
479
+ // ==========================================================================
480
+ // Initialization
481
+ // ==========================================================================
482
+ /**
483
+ * Initialize the workspace: create directories, write .orb templates,
484
+ * optionally initialize git.
485
+ *
486
+ * Safe to call multiple times — skips if already initialized.
487
+ */
488
+ async initialize() {
489
+ if (this.initialized) return;
490
+ const almadarDir = this.resolve(WORKSPACE_LAYOUT.ALMADAR_DIR);
491
+ const orbitalsDir = this.resolve(WORKSPACE_LAYOUT.ORBITALS_DIR);
492
+ await mkdir(almadarDir, { recursive: true });
493
+ await mkdir(orbitalsDir, { recursive: true });
494
+ await this.writeTemplateIfMissing(
495
+ WORKSPACE_LAYOUT.USER_MEMORY,
496
+ serializeOrb(createUserOrbTemplate(this.config.userId))
497
+ );
498
+ await this.writeTemplateIfMissing(
499
+ WORKSPACE_LAYOUT.PROJECT_MEMORY,
500
+ serializeOrb(createProjectOrbTemplate(
501
+ this.config.projectName ?? "Untitled",
502
+ this.config.appId
503
+ ))
504
+ );
505
+ await this.writeTemplateIfMissing(
506
+ WORKSPACE_LAYOUT.SCHEMA,
507
+ serializeOrb(createSchemaOrbTemplate(
508
+ this.config.projectName ?? "Untitled"
509
+ ))
510
+ );
511
+ if (this.config.gitEnabled !== false) {
512
+ this.gitSink = new GitSink(this.config.rootDir);
513
+ await this.gitSink.initialize();
514
+ this.sinkManager.register(this.gitSink);
515
+ const git = new GitClient(this.config.rootDir);
516
+ if (await git.isRepo()) {
517
+ await git.addAll();
518
+ await git.commit("init: workspace initialized");
519
+ }
520
+ }
521
+ this.initialized = true;
522
+ }
523
+ // ==========================================================================
524
+ // File Write Notifications
525
+ // ==========================================================================
526
+ /**
527
+ * Notify sinks that a file was written.
528
+ * Call this from the server when the agent writes a file.
529
+ *
530
+ * @param relativePath - Path relative to workspace root
531
+ * @param content - File content as string
532
+ * @param meta - Optional metadata override (auto-inferred if not provided)
533
+ */
534
+ async onFileWritten(relativePath, content, meta) {
535
+ const fullMeta = inferFileMeta(relativePath, meta);
536
+ return this.sinkManager.notifyFileWritten(relativePath, content, fullMeta);
537
+ }
538
+ // ==========================================================================
539
+ // Memory Operations
540
+ // ==========================================================================
541
+ /**
542
+ * Load memory from .orb files. Call at session start to provide
543
+ * the agent with user preferences and project context.
544
+ */
545
+ async loadMemory() {
546
+ const [user, project] = await Promise.all([
547
+ readOrbInstances(this.resolve(WORKSPACE_LAYOUT.USER_MEMORY)),
548
+ readOrbInstances(this.resolve(WORKSPACE_LAYOUT.PROJECT_MEMORY))
549
+ ]);
550
+ return { user, project };
551
+ }
552
+ /**
553
+ * Update memory .orb file instances. Call at session end to
554
+ * persist learned preferences and discovered domain knowledge.
555
+ */
556
+ async saveMemory(updates) {
557
+ const writes = [];
558
+ if (updates.user) {
559
+ writes.push(
560
+ writeOrbInstances(this.resolve(WORKSPACE_LAYOUT.USER_MEMORY), updates.user)
561
+ );
562
+ }
563
+ if (updates.project) {
564
+ writes.push(
565
+ writeOrbInstances(this.resolve(WORKSPACE_LAYOUT.PROJECT_MEMORY), updates.project)
566
+ );
567
+ }
568
+ await Promise.all(writes);
569
+ if (updates.user) {
570
+ const content = JSON.stringify(updates.user, null, 2);
571
+ await this.sinkManager.notifyFileWritten(
572
+ WORKSPACE_LAYOUT.USER_MEMORY,
573
+ content,
574
+ { fileType: "memory", sessionId: this.config.sessionId }
575
+ );
576
+ }
577
+ if (updates.project) {
578
+ const content = JSON.stringify(updates.project, null, 2);
579
+ await this.sinkManager.notifyFileWritten(
580
+ WORKSPACE_LAYOUT.PROJECT_MEMORY,
581
+ content,
582
+ { fileType: "memory", sessionId: this.config.sessionId }
583
+ );
584
+ }
585
+ }
586
+ // ==========================================================================
587
+ // Session End
588
+ // ==========================================================================
589
+ /**
590
+ * End the session: notify all sinks, create git tag.
591
+ * Call from the server when the agent session completes.
592
+ */
593
+ async endSession() {
594
+ return this.sinkManager.notifySessionEnd(this.config.sessionId);
595
+ }
596
+ // ==========================================================================
597
+ // Helpers
598
+ // ==========================================================================
599
+ async writeTemplateIfMissing(relativePath, content) {
600
+ const fullPath = this.resolve(relativePath);
601
+ try {
602
+ await access(fullPath);
603
+ } catch {
604
+ await writeOrb(fullPath, JSON.parse(content));
605
+ }
606
+ }
607
+ };
608
+ function inferFileMeta(relativePath, partial) {
609
+ if (partial?.fileType) {
610
+ return {
611
+ fileType: partial.fileType,
612
+ orbitalName: partial.orbitalName,
613
+ sessionId: partial.sessionId
614
+ };
615
+ }
616
+ if (relativePath.includes("/orbitals/") || relativePath.match(/\.orbitals\//)) {
617
+ const name = relativePath.split("/").pop()?.replace(/\.(orb|json)$/, "") ?? void 0;
618
+ return { fileType: "orbital", orbitalName: name, sessionId: partial?.sessionId };
619
+ }
620
+ if (relativePath.endsWith("schema.orb") || relativePath.endsWith("schema.json")) {
621
+ return { fileType: "schema", sessionId: partial?.sessionId };
622
+ }
623
+ if (relativePath.endsWith("user.orb") || relativePath.endsWith("project.orb")) {
624
+ return { fileType: "memory", sessionId: partial?.sessionId };
625
+ }
626
+ if (relativePath.endsWith("domain.txt")) {
627
+ return { fileType: "domain", sessionId: partial?.sessionId };
628
+ }
629
+ return { fileType: "other", sessionId: partial?.sessionId };
630
+ }
631
+
632
+ // src/workspace/sinks/firestore-sink.ts
633
+ var FirestoreSink = class {
634
+ constructor(config) {
635
+ this.name = "firestore";
636
+ this.config = config;
637
+ }
638
+ /** Update the appId after it's been assigned (e.g., on first schema write). */
639
+ setAppId(appId) {
640
+ this.config.appId = appId;
641
+ }
642
+ async onFileWritten(_path, content, meta) {
643
+ switch (meta.fileType) {
644
+ case "orbital": {
645
+ if (!meta.orbitalName) return;
646
+ const orbital = JSON.parse(content);
647
+ await this.config.saveOrbital(meta.orbitalName, orbital);
648
+ break;
649
+ }
650
+ case "schema": {
651
+ if (!this.config.saveSchema) return;
652
+ const schema = JSON.parse(content);
653
+ const result = await this.config.saveSchema(schema);
654
+ if (result.appId && !this.config.appId) {
655
+ this.config.appId = result.appId;
656
+ this.config.onAppCreated?.(result.appId);
657
+ }
658
+ break;
659
+ }
660
+ case "memory": {
661
+ if (!this.config.saveMemory) return;
662
+ const data = JSON.parse(content);
663
+ const memoryType = data?.name?.toLowerCase()?.replace("memory", "") || "unknown";
664
+ await this.config.saveMemory(memoryType, data);
665
+ break;
666
+ }
667
+ }
668
+ }
669
+ async onSessionEnd(_sessionId) {
670
+ }
671
+ };
672
+
673
+ export { FirestoreSink, GitClient, GitSink, SinkManager, WORKSPACE_LAYOUT, WorkspaceManager, createProjectOrbTemplate, createSchemaOrbTemplate, createUserOrbTemplate, parseOrb, readOrb, readOrbInstances, serializeOrb, writeOrb, writeOrbInstances };
674
+ //# sourceMappingURL=index.js.map
675
+ //# sourceMappingURL=index.js.map