engineering-memory 0.2.5 → 0.2.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engineering-memory",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -25,8 +25,26 @@ export const validationIds = [
25
25
  export class BridgeService {
26
26
  dependencies;
27
27
  taskQueues = new Map();
28
+ deferDeliveries;
29
+ backgroundDelivery = Promise.resolve();
28
30
  constructor(dependencies) {
29
31
  this.dependencies = dependencies;
32
+ this.deferDeliveries = dependencies.deferDeliveries ?? true;
33
+ }
34
+ deliverInBackground() {
35
+ if (!this.deferDeliveries)
36
+ return;
37
+ this.backgroundDelivery = this.backgroundDelivery.then(async () => {
38
+ try {
39
+ await this.flushOutbox();
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ });
45
+ }
46
+ async settleDeliveries() {
47
+ await this.backgroundDelivery;
30
48
  }
31
49
  async sessionBootstrap(input) {
32
50
  return await this.execute(async () => {
@@ -676,15 +694,31 @@ export class BridgeService {
676
694
  }));
677
695
  assertSafeToPersist(cleanJson({ entries }));
678
696
  const snapshot = await this.activeTaskSnapshot(input.taskId, undefined, input.repoRoot);
697
+ const body = cleanJson({
698
+ taskId: input.taskId,
699
+ entries,
700
+ expectedTaskVersion: snapshot.taskVersion,
701
+ });
702
+ await this.dependencies.gate.invalidateTask(input.taskId);
703
+ if (this.deferDeliveries) {
704
+ const queued = await this.dependencies.outbox.enqueue({
705
+ operation: 'task.reconcile',
706
+ method: 'POST',
707
+ path: endpoints.taskReconcile,
708
+ body,
709
+ });
710
+ this.deliverInBackground();
711
+ return asJsonValue({
712
+ reconciled: entries.map((entry) => entry.resourceId),
713
+ queued: true,
714
+ outboxId: queued.id,
715
+ deliveryStatus: 'pending',
716
+ });
717
+ }
679
718
  const response = await this.dependencies.client.request(endpoints.taskReconcile, {
680
719
  method: 'POST',
681
- body: cleanJson({
682
- taskId: input.taskId,
683
- entries,
684
- expectedTaskVersion: snapshot.taskVersion,
685
- }),
720
+ body,
686
721
  });
687
- await this.dependencies.gate.invalidateTask(input.taskId);
688
722
  return asJsonValue({ reconciliations: response.data });
689
723
  });
690
724
  }
@@ -1363,7 +1397,10 @@ export class BridgeService {
1363
1397
  assertSafeToPersist(cleanJson(safeInput));
1364
1398
  return await this.taskExclusive(input.taskId, async () => {
1365
1399
  await this.recoverJournalOutbox(input.projectId, input.taskSlug);
1366
- await this.flushOutbox();
1400
+ if (this.deferDeliveries)
1401
+ this.deliverInBackground();
1402
+ else
1403
+ await this.flushOutbox();
1367
1404
  const journalInput = {
1368
1405
  eventId: idempotencyKey,
1369
1406
  taskId: input.taskId,
@@ -1426,7 +1463,8 @@ export class BridgeService {
1426
1463
  await this.dependencies.activeContexts.updateTaskSnapshot(input.taskId, expectedTaskVersion + 1, pointer.lastSequence + 1);
1427
1464
  }
1428
1465
  const predecessorEntries = taskEntries.filter((entry) => entry.id !== queued.id);
1429
- if (predecessorEntries.length > 0) {
1466
+ if (predecessorEntries.length > 0 || this.deferDeliveries) {
1467
+ this.deliverInBackground();
1430
1468
  return asJsonValue({
1431
1469
  local: { directory: staged.directory, applied: staged.applied },
1432
1470
  queued: true,
@@ -45,7 +45,9 @@ answer in the design; do not spend the read there.
45
45
 
46
46
  Do not pull history for everything. Pull it for the records the task actually touches, and for anything the header shows a surprising number of corrections on. Record `task.checkpoint` with type `discovery` and update STATE, DECISIONS, DISCOVERY, and HANDOFF projections through the bridge.
47
47
 
48
- Send calls that do not feed each other in one batch rather than one at a time: reads of any kind, and proposals for different records. Reconcile every record the task touched in a single `task.reconcile` call with `entries`, not one call per record. Keep in order only what moves the task version, and what genuinely waits on another answer.
48
+ Send calls that do not feed each other in one batch rather than one at a time: reads of any kind, and proposals for different records. Reconcile every record the task touched in a single `task.reconcile` call with `entries`, not one call per record.
49
+
50
+ Checkpoints, recorded corrections and reconciliations return before the backend has them, reporting `deliveryStatus: 'pending'` with the task version they will occupy. That is a completed call, not a pending one: the journal is already durable, delivery is already under way, and `task.verify` refuses while anything remains undelivered. Do not wait for it, poll it, or send it again. Wait only for what the next step uses — a proposal's identifiers, an approval's revision, a prepared lease, and verification itself.
49
51
 
50
52
  Temporary code written to reach or force a path — a pinned state, a fixed service response, a jump straight to the screen — is allowed and expected, carries the marker `ENGINEERING-MEMORY-TEMPORARY` with its reason, and is removed before verification. `task.verify` refuses while any marker is in the tree and names every line, and the commit gate refuses while one is staged.
51
53