@nac3/forge-cli 1.14.0 → 1.16.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.
@@ -96,19 +96,27 @@ export const DOCTRINE_DIGEST = [
96
96
  + 'instruccion precisa, pending o ticket. Full: discover.',
97
97
  },
98
98
  {
99
- slugs: ['sizing'],
99
+ slugs: ['sizing', 'persistence-interface'],
100
100
  /* Deliberately terse: tests/prompt-invariants.test.ts caps the static
101
101
  * prompt, and a longer line here would have to come out of another
102
102
  * doctrine. The verbs carry the detail in their descriptions, and the
103
- * fixed option catalogue lives in docs/doctrine/sizing.md. */
103
+ * fixed option catalogue lives in docs/doctrine/sizing.md.
104
+ *
105
+ * The async-interface clause was compressed INTO this entry rather than
106
+ * added as a new one (13-oct-2026): there were 124 chars of prompt budget
107
+ * left, so the sizing text was tightened to pay for it. It belongs here
108
+ * anyway -- it is the half of the persistence decision that needs NO
109
+ * sizing input, and reading them together is the point. */
104
110
  rule: 'SIZE BEFORE YOU BUILD (G9, hard gate). Volumetry = entities x '
105
- + 'events/year x ROWS PER EVENT (every table it writes) + retention PER '
106
- + 'CLASS (business vs trace; 0 = forever = unbounded) + concurrency + '
107
- + 'HARDWARE (heap_cap_mb is the runtime heap ceiling, NOT machine RAM). '
108
- + 'Ask the owner, never invent it. Pick one option per axis from the '
109
- + 'FIXED catalogue (yujin.sizing.show); yujin.sizing.record REFUSES one '
110
- + 'outside its envelope and construction cannot start without an '
111
- + 'admissible record. Full: discover.',
111
+ + 'events/year x ROWS PER EVENT (every table) + retention PER CLASS '
112
+ + '(0 = forever = unbounded) + concurrency + HARDWARE (heap_cap_mb = '
113
+ + 'heap ceiling, NOT machine RAM). Ask the owner; never invent. One '
114
+ + 'option per axis from the FIXED catalogue (yujin.sizing.show); record '
115
+ + 'REFUSES one outside its envelope and construction cannot start '
116
+ + 'without it. NEEDS NO SIZING: every store/repo method declared async '
117
+ + 'from commit 1 -- await on a non-Promise is free, sync->async later '
118
+ + 'is every call site (Kikan 1543). yf audit persistence. '
119
+ + 'Full: discover.',
112
120
  },
113
121
  {
114
122
  slugs: ['concurrency-scale'],
@@ -1 +1 @@
1
- {"version":3,"file":"doctrine_digest.js","sourceRoot":"","sources":["../../src/chat/doctrine_digest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctrine_digest.js","sourceRoot":"","sources":["../../src/chat/doctrine_digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,MAAM,CAAC,MAAM,eAAe,GAA0B;IACpD;QACE,KAAK,EAAE,CAAC,sBAAsB,CAAC;QAC/B,IAAI,EACF,8DAA8D;cAC5D,6DAA6D;cAC7D,+DAA+D;cAC/D,uDAAuD;cACvD,6DAA6D;cAC7D,yDAAyD;cACzD,gEAAgE;cAChE,4DAA4D;cAC5D,mCAAmC;KACxC;IACD;QACE,KAAK,EAAE,CAAC,gBAAgB,CAAC;QACzB,IAAI,EACF,gEAAgE;cAC9D,0DAA0D;cAC1D,4CAA4C;KACjD;IACD;QACE,KAAK,EAAE,CAAC,YAAY,CAAC;QACrB,IAAI,EAAE,2FAA2F;KAClG;IACD;QACE,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,IAAI,EAAE,2IAA2I;KAClJ;IACD;QACE,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,IAAI,EAAE,qFAAqF;KAC5F;IACD;QACE,KAAK,EAAE,CAAC,UAAU,EAAE,iBAAiB,CAAC;QACtC,IAAI,EAAE,2IAA2I;KAClJ;IACD;QACE,KAAK,EAAE,CAAC,gBAAgB,CAAC;QACzB,IAAI,EAAE,uTAAuT;KAC9T;IACD;QACE,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,IAAI,EAAE,iGAAiG;KACxG;IACD;QACE,KAAK,EAAE,CAAC,iBAAiB,CAAC;QAC1B,IAAI,EAAE,qFAAqF;KAC5F;IACD;QACE,KAAK,EAAE,CAAC,iBAAiB,CAAC;QAC1B,IAAI,EAAE,4GAA4G;KACnH;IACD;QACE,KAAK,EAAE,CAAC,sBAAsB,CAAC;QAC/B,IAAI,EAAE,kJAAkJ;KACzJ;IACD;QACE,KAAK,EAAE,CAAC,uBAAuB,CAAC;QAChC,IAAI,EAAE,mFAAmF;KAC1F;IACD;QACE,KAAK,EAAE,CAAC,iBAAiB,CAAC;QAC1B,IAAI,EACF,+EAA+E;cAC7E,+EAA+E;cAC/E,+EAA+E;cAC/E,yEAAyE;cACzE,2EAA2E;cAC3E,kEAAkE;KACvE;IACD;QACE,KAAK,EAAE,CAAC,cAAc,CAAC;QACvB,IAAI,EACF,8EAA8E;cAC5E,gFAAgF;cAChF,gFAAgF;cAChF,+EAA+E;cAC/E,yEAAyE;cACzE,gFAAgF;cAChF,wEAAwE;cACxE,wDAAwD;KAC7D;IACD;QACE,KAAK,EAAE,CAAC,QAAQ,EAAE,uBAAuB,CAAC;QAC1C;;;;;;;;;mEAS2D;QAC3D,IAAI,EACF,gEAAgE;cAC9D,mEAAmE;cACnE,oEAAoE;cACpE,mEAAmE;cACnE,uEAAuE;cACvE,iEAAiE;cACjE,sEAAsE;cACtE,qEAAqE;cACrE,yDAAyD;cACzD,iBAAiB;KACtB;IACD;QACE,KAAK,EAAE,CAAC,mBAAmB,CAAC;QAC5B,IAAI,EACF,uEAAuE;cACrE,6EAA6E;cAC7E,4EAA4E;cAC5E,mEAAmE;cACnE,gCAAgC;KACrC;IACD;QACE,KAAK,EAAE,CAAC,uBAAuB,CAAC;QAChC,IAAI,EACF,yEAAyE;cACvE,4EAA4E;cAC5E,8EAA8E;cAC9E,2EAA2E;cAC3E,8EAA8E;cAC9E,qEAAqE;cACrE,uEAAuE;cACvE,6DAA6D;KAClE;IACD;QACE,KAAK,EAAE,CAAC,kBAAkB,CAAC;QAC3B,IAAI,EAAE,6XAA6X;KACpY;IACD;QACE,KAAK,EAAE,CAAC,UAAU,CAAC;QACnB,IAAI,EAAE,qeAAqe;KAC5e;IACD;QACE,KAAK,EAAE,CAAC,UAAU,CAAC;QACnB,IAAI,EAAE,iFAAiF;KACxF;IACD;QACE,KAAK,EAAE,CAAC,uBAAuB,CAAC;QAChC,IAAI,EAAE,+UAA+U;KACtV;IACD;QACE,KAAK,EAAE,CAAC,iBAAiB,EAAE,wBAAwB,CAAC;QACpD,IAAI,EAAE,wHAAwH;KAC/H;IACD;QACE,KAAK,EAAE,CAAC,cAAc,CAAC;QACvB,IAAI,EAAE,6RAA6R;KACpS;IACD;QACE,KAAK,EAAE,CAAC,sBAAsB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,aAAa,EAAE,kBAAkB,CAAC;QAC3G,IAAI,EAAE,gLAAgL;KACvL;CACF,CAAC;AAEF,6DAA6D;AAC7D,MAAM,UAAU,WAAW;IACzB,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAQD;uEACuE;AACvE,MAAM,UAAU,wBAAwB,CAAC,OAA8B,EAAE;IACvE,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3C,IAAI,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAC9E,MAAM,KAAK,GAAa;QACtB,mEAAmE;QACnE,2DAA2D;QAC3D,mEAAmE;QACnE,EAAE;QACF,gEAAgE;QAChE,6DAA6D;QAC7D,EAAE;KACH,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/chat/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/chat/server.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,7 @@ import { isAllowedSlot, listAllowedSlots } from '../core/provider_keys.js';
48
48
  import { toolStatusSection, startToolStatusRefresh, environmentLines } from './tool_status.js';
49
49
  import { RelayPublisher } from '../relay/relay_publisher.js';
50
50
  import { setInFlightTurn, clearInFlightTurn, inFlightTurn } from '../relay/in_flight_turn.js';
51
+ import { decideBeat, presenceSignature, PRESENCE_TICK_MS } from '../relay/presence_cadence.js';
51
52
  import { getInstanceIdentity } from '../relay/instance_identity.js';
52
53
  import { isMobilePaired, relayGate } from '../core/mobile_pairing_state.js';
53
54
  import { relayPoll } from '../relay/relay_client.js';
@@ -863,6 +864,18 @@ function broadcastToPanel(event, data) {
863
864
  catch { /* best-effort */ }
864
865
  }
865
866
  }
867
+ /* El latido de presencia, forzable desde el camino del turno. El tick de
868
+ * evaluacion (5s) ya detecta el cambio de estado, pero forzarlo en el arranque
869
+ * y el cierre del turno lo hace INSTANTANEO: es la informacion por la que el
870
+ * telefono existe ("que esta haciendo ahora"), y no tiene que pagar ni la
871
+ * resolucion del tick. Null mientras no hay consumidores de relay corriendo. */
872
+ let _forcePresenceBeat = null;
873
+ function forcePresenceBeat() {
874
+ try {
875
+ _forcePresenceBeat?.(true);
876
+ }
877
+ catch { /* best-effort */ }
878
+ }
866
879
  let _relayPub = null;
867
880
  function getRelayPublisher() {
868
881
  if (!relayEnabled())
@@ -1127,29 +1140,73 @@ function startDesktopCommandConsumer(port, coord = {}) {
1127
1140
  pollCommands, runTurn, onControl, reply,
1128
1141
  onError: () => { },
1129
1142
  });
1130
- /* Item 2 (cross-machine): advertise this instance's presence on a slow
1131
- * heartbeat (gated by relayEnabled -> only when a phone is paired) so the
1132
- * phone can list + pick instances across machines and TTL-expire dead ones. */
1133
- const presenceTimer = setInterval(() => {
1143
+ /* Item 2 (cross-machine): advertise this instance's presence so the phone
1144
+ * can list + pick instances across machines and TTL-expire dead ones.
1145
+ * Gated by relayEnabled -> only when a phone is paired.
1146
+ *
1147
+ * La CADENCIA la decide relay/presence_cadence.ts, no este timer: el timer
1148
+ * solo marca el pulso de EVALUACION. Medido contra el D1 (12-oct-2026), el
1149
+ * latido fijo de 15s era el 85% de la ventana retenida del relay y 34 de
1150
+ * los 40 eventos que trae un refresco -- ocioso, inundaba su propia ventana
1151
+ * y dejaba al telefono sin nada que mostrar. Ahora: 15s con turno en vuelo,
1152
+ * 300s ocioso, e inmediato cuando el estado cambia (que es lo que mantiene
1153
+ * instantaneo el anuncio del pedido en proceso). */
1154
+ let lastBeatAt = null;
1155
+ let lastSig = null;
1156
+ const beatPresence = (force = false) => {
1134
1157
  try {
1135
1158
  const pub = getRelayPublisher();
1136
1159
  if (!pub)
1137
1160
  return;
1138
1161
  const idn = getInstanceIdentity();
1139
1162
  const slug = _relayBoardCtx?.slug ?? null;
1163
+ const turn = inFlightTurn();
1164
+ const info = { hostname: idn.hostname, project_slug: slug, turn };
1165
+ const sig = presenceSignature(info);
1166
+ if (!force) {
1167
+ const d = decideBeat({
1168
+ now: Date.now(), lastBeatAt, lastSig, sig, working: !!turn,
1169
+ });
1170
+ if (!d.beat)
1171
+ return;
1172
+ }
1173
+ lastBeatAt = Date.now();
1174
+ lastSig = sig;
1140
1175
  pub.presence({
1141
1176
  hostname: idn.hostname, pid: idn.pid, port,
1142
1177
  ...(slug ? { project_slug: slug, project_name: slug } : {}),
1143
- turn: inFlightTurn(),
1178
+ turn,
1144
1179
  });
1145
1180
  void pub.flush();
1146
1181
  }
1147
1182
  catch { /* best-effort */ }
1148
- }, 15000);
1183
+ };
1184
+ const presenceTimer = setInterval(() => { beatPresence(); }, PRESENCE_TICK_MS);
1149
1185
  if (typeof presenceTimer.unref === 'function')
1150
1186
  presenceTimer.unref();
1187
+ _forcePresenceBeat = beatPresence;
1151
1188
  return {
1152
- stop() { clearInterval(peerTimer); clearInterval(presenceTimer); chat.stop(); control.stop(); },
1189
+ stop() {
1190
+ clearInterval(peerTimer);
1191
+ clearInterval(presenceTimer);
1192
+ /* Despedida: con la cadencia ociosa en 300s el TTL del telefono son 15
1193
+ * minutos, asi que una instancia que se cierra quedaria fantasma en el
1194
+ * selector todo ese rato. Un ultimo latido marcado `gone` la borra al
1195
+ * instante. Best-effort -- el TTL sigue siendo el respaldo si el
1196
+ * proceso muere sin pasar por aca. */
1197
+ try {
1198
+ const pub = getRelayPublisher();
1199
+ if (pub) {
1200
+ const idn = getInstanceIdentity();
1201
+ pub.presence({ hostname: idn.hostname, pid: idn.pid, port, gone: true });
1202
+ void pub.flush();
1203
+ }
1204
+ }
1205
+ catch { /* best-effort */ }
1206
+ _forcePresenceBeat = null;
1207
+ chat.stop();
1208
+ control.stop();
1209
+ },
1153
1210
  tickOnce: async () => { await refreshPeers(); await chat.tickOnce(); await control.tickOnce(); },
1154
1211
  };
1155
1212
  }
@@ -1366,10 +1423,17 @@ function relayForward(event, data) {
1366
1423
  pub.status('working', { tier: d.tier, provider: d.provider, model: d.model });
1367
1424
  pub.activity('remote running...', { kind: 'heartbeat' }); /* first line now; then every 60s */
1368
1425
  startRelayHeartbeat();
1426
+ /* El turno en vuelo viaja DENTRO del latido (in_flight_turn.ts): hay que
1427
+ * publicarlo ya, sin esperar el tick, o el telefono no sabe que hay algo
1428
+ * corriendo hasta la proxima evaluacion. */
1429
+ forcePresenceBeat();
1369
1430
  }
1370
1431
  else if (event === 'turn_complete') {
1371
1432
  stopRelayHeartbeat();
1372
1433
  pub.status('round_done');
1434
+ /* Simetrico: el latido tiene que dejar de anunciar el turno, o el
1435
+ * telefono sigue mostrando la burbuja "pensando" hasta el proximo. */
1436
+ forcePresenceBeat();
1373
1437
  /* refresh the phone's board after each turn (workflow/pendings may
1374
1438
  * have changed) -- the pizarron is the value the user keeps. */
1375
1439
  publishBoardSnapshot();