@inerrata-corporation/errata 2.0.6-dev.2504 → 2.0.6-dev.2506

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 (2) hide show
  1. package/errata.mjs +67 -9
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -24184,7 +24184,12 @@ function renderSnapshot(s) {
24184
24184
  if (s.pendingUpdate) {
24185
24185
  lines.push("### \u26A1 errata update available");
24186
24186
  lines.push(
24187
- `\`${s.pendingUpdate.current}\` \u2192 \`${s.pendingUpdate.latest}\` on the \`${s.pendingUpdate.channel}\` channel. Tell your user \u2014 or run \`errata update\` yourself if they've asked you to keep errata current. It restarts the daemon; that's safe mid-session (hooks fail open, MCP reconnects).`
24187
+ `\`${s.pendingUpdate.current}\` \u2192 \`${s.pendingUpdate.latest}\` on the \`${s.pendingUpdate.channel}\` channel. ` + (s.pendingUpdate.localBuildEntry ? (
24188
+ // A local build holds the lock and `errata update` cannot replace it, so
24189
+ // "run errata update" was an instruction that could never clear this
24190
+ // notice (dogfood 2026-09-20: it nagged every prompt for days).
24191
+ `This daemon is a LOCAL BUILD running from \`${s.pendingUpdate.localBuildEntry}\`, which \`errata update\` does not replace. Tell your user \u2014 or, if they've asked you to keep errata current: \`errata update\`, then \`errata stop\`, then \`errata dash\` to start the installed one. `
24192
+ ) : "Tell your user \u2014 or, if they've asked you to keep errata current, run `errata update` and then `errata stop`: update only INSTALLS, and the running daemon stays on the old build until it is restarted. ") + "A restart is safe mid-session (hooks fail open, MCP reconnects)."
24188
24193
  );
24189
24194
  lines.push("");
24190
24195
  }
@@ -70828,7 +70833,7 @@ var init_report_render = __esm({
70828
70833
  // src/cli.ts
70829
70834
  init_src6();
70830
70835
  import { closeSync as closeSync2, existsSync as existsSync33, openSync as openSync2, readFileSync as readFileSync32, renameSync as renameSync4, statSync as statSync8 } from "node:fs";
70831
- import { join as join37, resolve as pathResolve } from "node:path";
70836
+ import { join as join37, resolve as pathResolve2 } from "node:path";
70832
70837
  import { spawn as spawn3 } from "node:child_process";
70833
70838
 
70834
70839
  // src/daemon.ts
@@ -78138,7 +78143,7 @@ function createWatchBreaker(deps) {
78138
78143
  }
78139
78144
 
78140
78145
  // src/engine.ts
78141
- var DAEMON_VERSION = true ? "2.0.6-dev.2504" : "2.0.0-alpha.0";
78146
+ var DAEMON_VERSION = true ? "2.0.6-dev.2506" : "2.0.0-alpha.0";
78142
78147
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
78143
78148
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
78144
78149
  var GIT_OP_MUTE_MS = 4e3;
@@ -80515,6 +80520,7 @@ init_identity2();
80515
80520
  init_dist();
80516
80521
  init_src5();
80517
80522
  import { existsSync as existsSync32, readFileSync as readFileSync31, unlinkSync as unlinkSync3, writeFileSync as writeFileSync23 } from "node:fs";
80523
+ import { resolve as pathResolve } from "node:path";
80518
80524
 
80519
80525
  // src/principle-sync.ts
80520
80526
  init_src5();
@@ -81497,6 +81503,33 @@ init_paths();
81497
81503
 
81498
81504
  // src/lock.ts
81499
81505
  import { existsSync as existsSync29, readFileSync as readFileSync28 } from "node:fs";
81506
+ function daemonLockPayload(lock) {
81507
+ return JSON.stringify({
81508
+ pid: lock.pid,
81509
+ webUiUrl: lock.webUiUrl,
81510
+ startedAt: lock.processStartedAt,
81511
+ ...lock.wokeAt !== void 0 ? { wokeAt: lock.wokeAt } : {},
81512
+ ...lock.entry ? { entry: lock.entry } : {},
81513
+ ...lock.version ? { version: lock.version } : {}
81514
+ });
81515
+ }
81516
+ var normEntry = (p) => {
81517
+ const s = p.replace(/\\/g, "/").replace(/\/+$/, "");
81518
+ return /^[A-Za-z]:\//.test(s) ? s.toLowerCase() : s;
81519
+ };
81520
+ function isInstalledEntry(entry) {
81521
+ return /\/node_modules\/@inerrata-corporation\/errata\//.test(normEntry(entry) + "/");
81522
+ }
81523
+ function foreignDaemonNote(lock, selfEntry) {
81524
+ if (!lock.entry || normEntry(lock.entry) === normEntry(selfEntry)) return null;
81525
+ const what = isInstalledEntry(lock.entry) ? "another install" : "a LOCAL BUILD";
81526
+ return [
81527
+ `launched from ${what}, not this one${lock.version ? ` (it is ${lock.version})` : ""}:`,
81528
+ ` running: ${lock.entry}`,
81529
+ ` this: ${selfEntry}`,
81530
+ "`errata update` does not replace it. To move onto this install: errata stop, then errata dash."
81531
+ ];
81532
+ }
81500
81533
  function isProcessAlive(pid) {
81501
81534
  if (!pid || pid <= 0) return false;
81502
81535
  try {
@@ -84441,6 +84474,13 @@ var SessionAffinity = class {
84441
84474
  };
84442
84475
 
84443
84476
  // src/multi.ts
84477
+ var PROCESS_STARTED_AT = Date.now();
84478
+ var SELF_ENTRY = process.argv[1] ? pathResolve(process.argv[1]) : "";
84479
+ var LOCAL_BUILD_ENTRY = SELF_ENTRY && !isInstalledEntry(SELF_ENTRY) ? SELF_ENTRY : void 0;
84480
+ function withLaunchOrigin(pending) {
84481
+ if (!pending) return null;
84482
+ return LOCAL_BUILD_ENTRY ? { ...pending, localBuildEntry: LOCAL_BUILD_ENTRY } : pending;
84483
+ }
84444
84484
  var projectSymbolSalts = /* @__PURE__ */ new Map();
84445
84485
  async function resolveProjectSymbolSalt(client, projectId) {
84446
84486
  const cached2 = projectSymbolSalts.get(projectId);
@@ -84701,7 +84741,7 @@ async function startMultiDaemon(opts = {}) {
84701
84741
  apiKey: opts.apiKey,
84702
84742
  reviewUrl: () => `${baseUrl}/ws/${id}/review`,
84703
84743
  sharedStore,
84704
- pendingUpdate: () => serverPending ?? updatePoller?.current() ?? null,
84744
+ pendingUpdate: () => withLaunchOrigin(serverPending ?? updatePoller?.current() ?? null),
84705
84745
  // Ops-gated (default OFF): the 🚨 notice reads as "errata broke my
84706
84746
  // machine" to a non-operator. Detection + ledger run regardless — only
84707
84747
  // this push surface (and the toast, gated in notifyOpsEvent) is scoped.
@@ -84784,7 +84824,14 @@ async function startMultiDaemon(opts = {}) {
84784
84824
  try {
84785
84825
  writeFileSync23(
84786
84826
  rec.engine.paths.daemonLock,
84787
- JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
84827
+ daemonLockPayload({
84828
+ pid: process.pid,
84829
+ webUiUrl: `${baseUrl}/ws/${rec.id}`,
84830
+ processStartedAt: PROCESS_STARTED_AT,
84831
+ entry: SELF_ENTRY,
84832
+ version: DAEMON_VERSION,
84833
+ wokeAt: Date.now()
84834
+ }),
84788
84835
  "utf8"
84789
84836
  );
84790
84837
  registerWorkspace(rec.engine.profile, rec.root);
@@ -84814,7 +84861,7 @@ async function startMultiDaemon(opts = {}) {
84814
84861
  "/",
84815
84862
  (c) => c.json({
84816
84863
  daemonVersion: DAEMON_VERSION,
84817
- pendingUpdate: updatePoller?.current() ?? null,
84864
+ pendingUpdate: withLaunchOrigin(updatePoller?.current() ?? null),
84818
84865
  projects: records.map((r) => ({
84819
84866
  id: r.id,
84820
84867
  name: r.entry.name,
@@ -85088,7 +85135,7 @@ async function startMultiDaemon(opts = {}) {
85088
85135
  ensureDir(globalDir());
85089
85136
  writeFileSync23(
85090
85137
  lockPath,
85091
- JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
85138
+ daemonLockPayload({ pid: process.pid, webUiUrl: baseUrl, processStartedAt: PROCESS_STARTED_AT, entry: SELF_ENTRY, version: DAEMON_VERSION }),
85092
85139
  "utf8"
85093
85140
  );
85094
85141
  } catch {
@@ -85097,7 +85144,14 @@ async function startMultiDaemon(opts = {}) {
85097
85144
  try {
85098
85145
  writeFileSync23(
85099
85146
  r.engine.paths.daemonLock,
85100
- JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
85147
+ daemonLockPayload({
85148
+ pid: process.pid,
85149
+ webUiUrl: `${baseUrl}/ws/${r.id}`,
85150
+ processStartedAt: PROCESS_STARTED_AT,
85151
+ entry: SELF_ENTRY,
85152
+ version: DAEMON_VERSION,
85153
+ wokeAt: PROCESS_STARTED_AT
85154
+ }),
85101
85155
  "utf8"
85102
85156
  );
85103
85157
  registerWorkspace(r.engine.profile, r.root);
@@ -87238,6 +87292,10 @@ async function cmdStatus() {
87238
87292
  console.log(
87239
87293
  ` daemon: ${running ? `running \xB7 pid ${running.pid} \xB7 ${running.webUiUrl ?? "(running)"}` : "not running (run: errata start)"}`
87240
87294
  );
87295
+ if (running && process.argv[1]) {
87296
+ const note = foreignDaemonNote(running, pathResolve2(process.argv[1]));
87297
+ if (note) for (const l of note) console.log(` \u26A0 ${l}`);
87298
+ }
87241
87299
  if (running?.webUiUrl) {
87242
87300
  try {
87243
87301
  const res = await fetch(`${running.webUiUrl}/health`, {
@@ -87387,7 +87445,7 @@ async function cmdWhoami(args2) {
87387
87445
  const cfg = loadConfig();
87388
87446
  const wIdx = args2.indexOf("--workspace");
87389
87447
  if (wIdx >= 0) {
87390
- const path2 = pathResolve(args2[wIdx + 1] ?? process.cwd());
87448
+ const path2 = pathResolve2(args2[wIdx + 1] ?? process.cwd());
87391
87449
  const entry = workspaceEntryForPath(path2);
87392
87450
  const identity = resolveWorkspaceIdentity(cfg, entry);
87393
87451
  const lines = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.6-dev.2504",
3
+ "version": "2.0.6-dev.2506",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {