@inerrata-corporation/errata 2.0.6-dev.2081 → 2.0.6-dev.2115
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/errata.mjs +119 -14
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -77056,7 +77056,7 @@ function createWatchBreaker(deps) {
|
|
|
77056
77056
|
}
|
|
77057
77057
|
|
|
77058
77058
|
// src/engine.ts
|
|
77059
|
-
var DAEMON_VERSION = true ? "2.0.6-dev.
|
|
77059
|
+
var DAEMON_VERSION = true ? "2.0.6-dev.2115" : "2.0.0-alpha.0";
|
|
77060
77060
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
77061
77061
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
77062
77062
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -82578,10 +82578,21 @@ init_cloud_auth();
|
|
|
82578
82578
|
import { createServer } from "node:http";
|
|
82579
82579
|
var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
82580
82580
|
var strip = (u) => u.replace(/\/+$/, "");
|
|
82581
|
-
function deviceEndpoints(tokenEndpoint) {
|
|
82581
|
+
function deviceEndpoints(tokenEndpoint, deviceAuthorizationEndpoint) {
|
|
82582
82582
|
const token = new URL(tokenEndpoint);
|
|
82583
82583
|
const authRoot = token.pathname.replace(/\/(?:oauth2|mcp)\/token\/?$/, "");
|
|
82584
|
-
if (authRoot === token.pathname)
|
|
82584
|
+
if (authRoot === token.pathname) {
|
|
82585
|
+
if (deviceAuthorizationEndpoint) {
|
|
82586
|
+
const device = new URL(deviceAuthorizationEndpoint);
|
|
82587
|
+
const code = `${device.origin}${device.pathname.replace(/\/+$/, "")}`;
|
|
82588
|
+
return {
|
|
82589
|
+
code,
|
|
82590
|
+
token: `${code}/token`,
|
|
82591
|
+
resource: new URL("/api/gate/session-token", device.origin).toString()
|
|
82592
|
+
};
|
|
82593
|
+
}
|
|
82594
|
+
throw new Error("authorization server exposes no device endpoint");
|
|
82595
|
+
}
|
|
82585
82596
|
const prefix = authRoot.replace(/\/api\/auth\/?$/, "");
|
|
82586
82597
|
const at = (path2) => new URL(`${path2}`, `${token.origin}${prefix || "/"}`).toString();
|
|
82587
82598
|
return {
|
|
@@ -82593,7 +82604,7 @@ function deviceEndpoints(tokenEndpoint) {
|
|
|
82593
82604
|
async function loginOAuthDevice(opts) {
|
|
82594
82605
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
82595
82606
|
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82596
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82607
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint, endpoints.deviceAuthorizationEndpoint);
|
|
82597
82608
|
const clientId = oauthClientId();
|
|
82598
82609
|
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
82599
82610
|
const codeResponse = await fetchFn(device.code, {
|
|
@@ -82692,7 +82703,8 @@ async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
|
|
|
82692
82703
|
return {
|
|
82693
82704
|
authorizationEndpoint: j.authorization_endpoint,
|
|
82694
82705
|
tokenEndpoint: j.token_endpoint,
|
|
82695
|
-
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {}
|
|
82706
|
+
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {},
|
|
82707
|
+
...j.device_authorization_endpoint ? { deviceAuthorizationEndpoint: j.device_authorization_endpoint } : {}
|
|
82696
82708
|
};
|
|
82697
82709
|
}
|
|
82698
82710
|
}
|
|
@@ -82809,7 +82821,7 @@ function isDecision(value) {
|
|
|
82809
82821
|
async function linkThroughConsole(opts) {
|
|
82810
82822
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
82811
82823
|
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82812
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82824
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint, endpoints.deviceAuthorizationEndpoint);
|
|
82813
82825
|
const clientId = oauthClientId();
|
|
82814
82826
|
const link = {
|
|
82815
82827
|
locator: opts.facts.locator,
|
|
@@ -83159,6 +83171,76 @@ function codexWakeCandidates(input) {
|
|
|
83159
83171
|
return out2;
|
|
83160
83172
|
}
|
|
83161
83173
|
|
|
83174
|
+
// src/hook-route.ts
|
|
83175
|
+
function msysToWindowsPath(p, platform = process.platform) {
|
|
83176
|
+
if (platform !== "win32") return p;
|
|
83177
|
+
const m = /^\/([a-zA-Z])(\/.*)?$/.exec(p);
|
|
83178
|
+
return m ? `${m[1].toUpperCase()}:${m[2] ?? "/"}` : p;
|
|
83179
|
+
}
|
|
83180
|
+
var SHELL_BREAK = /[\s"'`;&|()<>=]+/;
|
|
83181
|
+
function absolutePathsInCommand(command, platform = process.platform) {
|
|
83182
|
+
const out2 = [];
|
|
83183
|
+
for (const raw2 of command.split(SHELL_BREAK)) {
|
|
83184
|
+
const token = raw2.replace(/^[:,]+/, "").replace(/[,:]+$/, "");
|
|
83185
|
+
if (!token) continue;
|
|
83186
|
+
if (/^[a-zA-Z]:[\\/]/.test(token)) {
|
|
83187
|
+
out2.push(token);
|
|
83188
|
+
} else if (token.startsWith("/") && !token.startsWith("//")) {
|
|
83189
|
+
if (platform === "win32") {
|
|
83190
|
+
if (/^\/[a-zA-Z](\/|$)/.test(token)) out2.push(msysToWindowsPath(token, platform));
|
|
83191
|
+
} else if (token.length > 1) {
|
|
83192
|
+
out2.push(token);
|
|
83193
|
+
}
|
|
83194
|
+
}
|
|
83195
|
+
}
|
|
83196
|
+
return out2;
|
|
83197
|
+
}
|
|
83198
|
+
function hookPathCandidates(body2, platform = process.platform) {
|
|
83199
|
+
const input = body2["tool_input"] ?? {};
|
|
83200
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
83201
|
+
const out2 = [];
|
|
83202
|
+
for (const key of ["file_path", "notebook_path", "path"]) {
|
|
83203
|
+
const v = str(input[key]);
|
|
83204
|
+
if (v) out2.push(msysToWindowsPath(v, platform));
|
|
83205
|
+
}
|
|
83206
|
+
const command = str(input["command"]);
|
|
83207
|
+
if (command) out2.push(...absolutePathsInCommand(command, platform));
|
|
83208
|
+
const cwd = str(body2["cwd"]);
|
|
83209
|
+
if (cwd) out2.push(msysToWindowsPath(cwd, platform));
|
|
83210
|
+
return [...new Set(out2)];
|
|
83211
|
+
}
|
|
83212
|
+
var SESSION_AFFINITY_TTL_MS = 30 * 6e4;
|
|
83213
|
+
var SessionAffinity = class {
|
|
83214
|
+
constructor(ttlMs = SESSION_AFFINITY_TTL_MS, maxSessions = 500) {
|
|
83215
|
+
this.ttlMs = ttlMs;
|
|
83216
|
+
this.maxSessions = maxSessions;
|
|
83217
|
+
}
|
|
83218
|
+
bySession = /* @__PURE__ */ new Map();
|
|
83219
|
+
note(sessionId, root, now = Date.now()) {
|
|
83220
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) return;
|
|
83221
|
+
this.bySession.delete(sessionId);
|
|
83222
|
+
this.bySession.set(sessionId, { root, at: now });
|
|
83223
|
+
while (this.bySession.size > this.maxSessions) {
|
|
83224
|
+
const oldest = this.bySession.keys().next().value;
|
|
83225
|
+
if (oldest === void 0) break;
|
|
83226
|
+
this.bySession.delete(oldest);
|
|
83227
|
+
}
|
|
83228
|
+
}
|
|
83229
|
+
rootFor(sessionId, now = Date.now()) {
|
|
83230
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) return null;
|
|
83231
|
+
const hit = this.bySession.get(sessionId);
|
|
83232
|
+
if (!hit) return null;
|
|
83233
|
+
if (now - hit.at > this.ttlMs) {
|
|
83234
|
+
this.bySession.delete(sessionId);
|
|
83235
|
+
return null;
|
|
83236
|
+
}
|
|
83237
|
+
return hit.root;
|
|
83238
|
+
}
|
|
83239
|
+
forget(sessionId) {
|
|
83240
|
+
if (typeof sessionId === "string") this.bySession.delete(sessionId);
|
|
83241
|
+
}
|
|
83242
|
+
};
|
|
83243
|
+
|
|
83162
83244
|
// src/multi.ts
|
|
83163
83245
|
var projectSymbolSalts = /* @__PURE__ */ new Map();
|
|
83164
83246
|
async function resolveProjectSymbolSalt(client, projectId) {
|
|
@@ -83609,7 +83691,8 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83609
83691
|
}))
|
|
83610
83692
|
})
|
|
83611
83693
|
);
|
|
83612
|
-
const
|
|
83694
|
+
const sessionAffinity = new SessionAffinity();
|
|
83695
|
+
const forward = async (c, pathInBody, opts2 = {}) => {
|
|
83613
83696
|
const raw2 = await c.req.text();
|
|
83614
83697
|
let body2 = {};
|
|
83615
83698
|
try {
|
|
@@ -83618,7 +83701,21 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83618
83701
|
return c.json({ error: "bad-json" }, 400);
|
|
83619
83702
|
}
|
|
83620
83703
|
lastHook = { at: Date.now(), event: typeof body2["hook_event_name"] === "string" ? body2["hook_event_name"] : c.req.path };
|
|
83621
|
-
|
|
83704
|
+
const primary = pathInBody(body2);
|
|
83705
|
+
const others = (opts2.extraPaths?.(body2) ?? []).filter((p) => p !== primary);
|
|
83706
|
+
let owner = ownerOf(records, primary);
|
|
83707
|
+
for (const p of others) {
|
|
83708
|
+
if (owner) break;
|
|
83709
|
+
owner = ownerOf(records, p);
|
|
83710
|
+
}
|
|
83711
|
+
if (!owner && others.length > 0) {
|
|
83712
|
+
const registryRoots = listWorkspaceEntries().map((e) => e.path);
|
|
83713
|
+
const registered = others.map((p) => pickOwnerRoot(registryRoots, p)).find((r) => r != null);
|
|
83714
|
+
if (registered && attachWorkspace(registered).attached) {
|
|
83715
|
+
owner = records.find((r) => r.root === registered) ?? null;
|
|
83716
|
+
if (owner) console.log(`[errata] woke workspace ${owner.entry.name}`);
|
|
83717
|
+
}
|
|
83718
|
+
}
|
|
83622
83719
|
if (!owner) {
|
|
83623
83720
|
const missPath = pathInBody(body2);
|
|
83624
83721
|
const registeredRoot = missPath ? pickOwnerRoot(listWorkspaceEntries().map((e) => e.path), missPath) : null;
|
|
@@ -83628,10 +83725,18 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83628
83725
|
if (owner) console.log(`[errata] woke workspace ${owner.entry.name}`);
|
|
83629
83726
|
}
|
|
83630
83727
|
}
|
|
83728
|
+
if (!owner && opts2.affinity === "follow") {
|
|
83729
|
+
const root = sessionAffinity.rootFor(body2["session_id"]);
|
|
83730
|
+
if (root) {
|
|
83731
|
+
owner = records.find((r) => r.root === root) ?? null;
|
|
83732
|
+
if (!owner && attachWorkspace(root).attached) owner = records.find((r) => r.root === root) ?? null;
|
|
83733
|
+
}
|
|
83734
|
+
}
|
|
83631
83735
|
if (!owner) {
|
|
83632
|
-
rootAdopter.noteMiss(
|
|
83736
|
+
rootAdopter.noteMiss(primary);
|
|
83633
83737
|
return c.json({ error: "no-matching-project" }, 404);
|
|
83634
83738
|
}
|
|
83739
|
+
if (opts2.affinity === "note") sessionAffinity.note(body2["session_id"], owner.root);
|
|
83635
83740
|
owner.lastHookAt = Date.now();
|
|
83636
83741
|
const sub = c.req.path;
|
|
83637
83742
|
const done = markPass(`${sub}:${owner.entry.name}`);
|
|
@@ -83654,7 +83759,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83654
83759
|
const fp = input["file_path"];
|
|
83655
83760
|
const cwd = b["cwd"];
|
|
83656
83761
|
return (typeof fp === "string" ? fp : void 0) ?? (typeof cwd === "string" ? cwd : void 0);
|
|
83657
|
-
})
|
|
83762
|
+
}, { extraPaths: (b) => hookPathCandidates(b), affinity: "note" })
|
|
83658
83763
|
);
|
|
83659
83764
|
app.post(
|
|
83660
83765
|
"/api/diagnostics",
|
|
@@ -83664,10 +83769,10 @@ async function startMultiDaemon(opts = {}) {
|
|
|
83664
83769
|
})
|
|
83665
83770
|
);
|
|
83666
83771
|
const cwdOf = (b) => typeof b["cwd"] === "string" ? b["cwd"] : void 0;
|
|
83667
|
-
app.post("/api/turn", (c) => forward(c, cwdOf));
|
|
83668
|
-
app.post("/api/message", (c) => forward(c, cwdOf));
|
|
83669
|
-
app.post("/api/session-end", (c) => forward(c, cwdOf));
|
|
83670
|
-
app.post("/api/context-inject", (c) => forward(c, cwdOf));
|
|
83772
|
+
app.post("/api/turn", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
83773
|
+
app.post("/api/message", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
83774
|
+
app.post("/api/session-end", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
83775
|
+
app.post("/api/context-inject", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
83671
83776
|
for (const r of records) {
|
|
83672
83777
|
mountedIds.add(r.id);
|
|
83673
83778
|
app.route(`/ws/${r.id}`, r.webApp);
|