@inerrata-corporation/errata 2.0.0-dev.32 → 2.0.0-dev.34

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 +106 -32
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -20434,6 +20434,37 @@ async function postToken(fetchFn, tokenEndpoint, params, timeoutMs = 15e3) {
20434
20434
  clearTimeout(tid);
20435
20435
  }
20436
20436
  }
20437
+ async function registerOAuthClient(fetchFn, registrationEndpoint, p, timeoutMs = 15e3) {
20438
+ const ac = new AbortController();
20439
+ const tid = setTimeout(() => ac.abort(), timeoutMs);
20440
+ try {
20441
+ const res = await fetchFn(registrationEndpoint, {
20442
+ method: "POST",
20443
+ headers: {
20444
+ "content-type": "application/json",
20445
+ accept: "application/json"
20446
+ },
20447
+ body: JSON.stringify({
20448
+ redirect_uris: [p.redirectUri],
20449
+ token_endpoint_auth_method: "none",
20450
+ grant_types: ["authorization_code", "refresh_token"],
20451
+ response_types: ["code"],
20452
+ client_name: p.clientName ?? "errata daemon",
20453
+ scope: p.scope
20454
+ }),
20455
+ signal: ac.signal
20456
+ });
20457
+ if (!res.ok) {
20458
+ const text = await res.text();
20459
+ throw new Error(`client registration failed: HTTP ${res.status} ${text.slice(0, 200)}`);
20460
+ }
20461
+ const j = await res.json();
20462
+ if (!j.client_id) throw new Error("client registration returned no client_id");
20463
+ return { clientId: j.client_id };
20464
+ } finally {
20465
+ clearTimeout(tid);
20466
+ }
20467
+ }
20437
20468
  function exchangeAuthorizationCode(fetchFn, tokenEndpoint, p) {
20438
20469
  return postToken(fetchFn, tokenEndpoint, {
20439
20470
  grant_type: "authorization_code",
@@ -20921,6 +20952,7 @@ function defaultConfig() {
20921
20952
  accessToken: null,
20922
20953
  refreshToken: null,
20923
20954
  tokenEndpoint: null,
20955
+ oauthClientId: null,
20924
20956
  userId: null,
20925
20957
  email: null,
20926
20958
  consent: { sync: false, telemetry: false, contributePackages: false },
@@ -21189,7 +21221,7 @@ function authedCloudClient(cfg, opts = {}) {
21189
21221
  ...tokenEndpoint && cfg.refreshToken ? {
21190
21222
  refreshFn: (rt) => refreshAccessToken(opts.fetchFn ?? fetch, tokenEndpoint, {
21191
21223
  refreshToken: rt,
21192
- clientId: oauthClientId()
21224
+ clientId: cfg.oauthClientId ?? oauthClientId()
21193
21225
  }),
21194
21226
  // Persist the rotated tokens so the next process starts fresh.
21195
21227
  onTokens: (t) => {
@@ -41846,7 +41878,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
41846
41878
  }
41847
41879
 
41848
41880
  // src/engine.ts
41849
- var DAEMON_VERSION = true ? "2.0.0-dev.32" : "2.0.0-alpha.0";
41881
+ var DAEMON_VERSION = true ? "2.0.0-dev.34" : "2.0.0-alpha.0";
41850
41882
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
41851
41883
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
41852
41884
  var GIT_OP_MUTE_MS = 4e3;
@@ -43037,6 +43069,7 @@ async function startDaemon(opts) {
43037
43069
  merged.accessToken = null;
43038
43070
  merged.refreshToken = null;
43039
43071
  merged.tokenEndpoint = null;
43072
+ merged.oauthClientId = null;
43040
43073
  }
43041
43074
  const cloud = authedCloudClient(merged);
43042
43075
  let webUiUrl = "";
@@ -43801,6 +43834,7 @@ async function startMultiDaemon(opts = {}) {
43801
43834
  initialCfg.accessToken = null;
43802
43835
  initialCfg.refreshToken = null;
43803
43836
  initialCfg.tokenEndpoint = null;
43837
+ initialCfg.oauthClientId = null;
43804
43838
  }
43805
43839
  const cloud = authedCloudClient(initialCfg, { timeoutMs: CLOUD_TIMEOUT_MS });
43806
43840
  const cloudNow = () => {
@@ -43812,6 +43846,7 @@ async function startMultiDaemon(opts = {}) {
43812
43846
  current.accessToken = null;
43813
43847
  current.refreshToken = null;
43814
43848
  current.tokenEndpoint = null;
43849
+ current.oauthClientId = null;
43815
43850
  }
43816
43851
  return authedCloudClient(current, { timeoutMs: CLOUD_TIMEOUT_MS });
43817
43852
  };
@@ -44424,6 +44459,7 @@ init_cloud_endpoint_policy();
44424
44459
  init_src6();
44425
44460
  init_cloud_auth();
44426
44461
  import { createServer } from "node:http";
44462
+ var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
44427
44463
  var strip = (u) => u.replace(/\/+$/, "");
44428
44464
  async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
44429
44465
  let consoleUrl = cloudUrl;
@@ -44440,7 +44476,11 @@ async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
44440
44476
  if (asm.ok) {
44441
44477
  const j = await asm.json();
44442
44478
  if (j.authorization_endpoint && j.token_endpoint) {
44443
- return { authorizationEndpoint: j.authorization_endpoint, tokenEndpoint: j.token_endpoint };
44479
+ return {
44480
+ authorizationEndpoint: j.authorization_endpoint,
44481
+ tokenEndpoint: j.token_endpoint,
44482
+ ...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {}
44483
+ };
44444
44484
  }
44445
44485
  }
44446
44486
  } catch {
@@ -44467,8 +44507,8 @@ async function loginOAuthLoopback(opts) {
44467
44507
  const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
44468
44508
  const pkce = generatePkce();
44469
44509
  const state = randomState();
44470
- const clientId = oauthClientId();
44471
- const { code, redirectUri } = await new Promise(
44510
+ const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
44511
+ const { code, redirectUri, clientId } = await new Promise(
44472
44512
  (resolve5, reject) => {
44473
44513
  const server = createServer((req, res) => {
44474
44514
  const u = new URL(req.url ?? "/", "http://127.0.0.1");
@@ -44492,24 +44532,40 @@ async function loginOAuthLoopback(opts) {
44492
44532
  res.writeHead(200, { "content-type": "text/html" });
44493
44533
  res.end("<html><body>inErrata: you're logged in. You can close this tab.</body></html>");
44494
44534
  server.close();
44495
- resolve5({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback` });
44535
+ resolve5({ code: code2, redirectUri: `http://127.0.0.1:${port}/callback`, clientId: activeClientId });
44496
44536
  });
44537
+ let activeClientId = oauthClientId();
44497
44538
  server.on("error", reject);
44498
44539
  server.listen(0, "127.0.0.1", () => {
44499
- const addr2 = server.address();
44500
- const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
44501
- const redirectUri2 = `http://127.0.0.1:${port}/callback`;
44502
- const url2 = buildAuthorizeUrl(endpoints.authorizationEndpoint, {
44503
- clientId,
44504
- redirectUri: redirectUri2,
44505
- scope: opts.scope ?? "openid profile",
44506
- state,
44507
- challenge: pkce.challenge,
44508
- method: pkce.method
44509
- });
44510
- if (opts.open) opts.open(url2);
44511
- else console.log(`approve this login in your browser:
44540
+ void (async () => {
44541
+ try {
44542
+ const addr2 = server.address();
44543
+ const port = typeof addr2 === "object" && addr2 ? addr2.port : 0;
44544
+ const redirectUri2 = `http://127.0.0.1:${port}/callback`;
44545
+ if (endpoints.registrationEndpoint) {
44546
+ const registered = await registerOAuthClient(fetchFn, endpoints.registrationEndpoint, {
44547
+ redirectUri: redirectUri2,
44548
+ scope,
44549
+ clientName: "errata daemon"
44550
+ });
44551
+ activeClientId = registered.clientId;
44552
+ }
44553
+ const url2 = buildAuthorizeUrl(endpoints.authorizationEndpoint, {
44554
+ clientId: activeClientId,
44555
+ redirectUri: redirectUri2,
44556
+ scope,
44557
+ state,
44558
+ challenge: pkce.challenge,
44559
+ method: pkce.method
44560
+ });
44561
+ if (opts.open) opts.open(url2);
44562
+ else console.log(`approve this login in your browser:
44512
44563
  ${url2}`);
44564
+ } catch (err2) {
44565
+ server.close();
44566
+ reject(err2);
44567
+ }
44568
+ })();
44513
44569
  });
44514
44570
  if (opts.timeoutMs) {
44515
44571
  setTimeout(() => {
@@ -44525,7 +44581,7 @@ async function loginOAuthLoopback(opts) {
44525
44581
  redirectUri,
44526
44582
  clientId
44527
44583
  });
44528
- return { tokens, tokenEndpoint: endpoints.tokenEndpoint };
44584
+ return { tokens, tokenEndpoint: endpoints.tokenEndpoint, clientId };
44529
44585
  }
44530
44586
 
44531
44587
  // src/update.ts
@@ -44617,6 +44673,15 @@ function parseBurstArgs(args2) {
44617
44673
  };
44618
44674
  }
44619
44675
 
44676
+ // src/login-mode.ts
44677
+ var OAUTH_DEFAULT_ENV = "ERRATA_DAEMON_OAUTH_DEFAULT";
44678
+ function isDaemonOAuthDefaultEnabled(env2 = process.env) {
44679
+ return env2[OAUTH_DEFAULT_ENV] === "1";
44680
+ }
44681
+ function shouldUseOAuthLogin(flags2, env2 = process.env) {
44682
+ return Boolean(flags2.oauth || !flags2.device && isDaemonOAuthDefaultEnabled(env2));
44683
+ }
44684
+
44620
44685
  // src/consolidation-trigger.ts
44621
44686
  var DEFAULT_CONSOLIDATION_POLICY = {
44622
44687
  baseFloorMs: 6e4,
@@ -44793,7 +44858,7 @@ Commands:
44793
44858
  Flags: --port N (default 7891)
44794
44859
  mcp Run the MCP stdio server \u2014 the agent's full errata tool
44795
44860
  surface (navigation, problems, claims, burst, health)
44796
- login Sign in with the cloud (OAuth by default; --device for legacy)
44861
+ login Sign in with the cloud (device-code by default; --oauth for OAuth)
44797
44862
  logout Clear local cloud credentials
44798
44863
  sync now Flush outbox to the cloud once
44799
44864
  privacy Show what is collected/scrubbed + your consent state
@@ -44808,6 +44873,7 @@ Commands:
44808
44873
  Environment:
44809
44874
  ERRATA_CLOUD_URL Cloud base URL (default ${DEFAULT_CLOUD_URL})
44810
44875
  ERRATA_ALLOW_DIRECT_V1_CLOUD=1 Allow non-local legacy v1 cloud testing
44876
+ ${OAUTH_DEFAULT_ENV}=1 Internal dogfood: plain \`errata login\` uses OAuth
44811
44877
  `);
44812
44878
  }
44813
44879
  function resolveHookPort(explicit) {
@@ -45117,6 +45183,7 @@ async function applyToken(cfg, token) {
45117
45183
  cfg.accessToken = null;
45118
45184
  cfg.refreshToken = null;
45119
45185
  cfg.tokenEndpoint = null;
45186
+ cfg.oauthClientId = null;
45120
45187
  cfg.userId = me.agentId;
45121
45188
  cfg.email = me.handle;
45122
45189
  saveConfig(cfg);
@@ -45158,19 +45225,24 @@ async function cmdLoginOAuth(cfg) {
45158
45225
  process.exitCode = 1;
45159
45226
  return;
45160
45227
  }
45161
- cfg.accessToken = result.tokens.accessToken;
45162
- cfg.refreshToken = result.tokens.refreshToken ?? null;
45163
- cfg.tokenEndpoint = result.tokenEndpoint;
45164
- cfg.apiKey = null;
45165
- saveConfig(cfg);
45228
+ const nextCfg = {
45229
+ ...cfg,
45230
+ accessToken: result.tokens.accessToken,
45231
+ refreshToken: result.tokens.refreshToken ?? null,
45232
+ tokenEndpoint: result.tokenEndpoint,
45233
+ oauthClientId: result.clientId,
45234
+ apiKey: null
45235
+ };
45166
45236
  try {
45167
- const me = await authedCloudClient(cfg).me();
45168
- cfg.userId = me.agentId;
45169
- cfg.email = me.handle;
45170
- saveConfig(cfg);
45237
+ const me = await authedCloudClient(nextCfg).me();
45238
+ nextCfg.userId = me.agentId;
45239
+ nextCfg.email = me.handle;
45240
+ saveConfig(nextCfg);
45171
45241
  console.log(`logged in as ${me.handle} (${me.tier}) \u2014 tokens stored at ${globalConfigPath()}`);
45172
45242
  } catch (err2) {
45173
- console.warn(`signed in, but identity check failed: ${err2 instanceof Error ? err2.message : err2}`);
45243
+ console.error(`signed in, but identity check failed: ${err2 instanceof Error ? err2.message : err2}`);
45244
+ console.error(` credentials were not stored; try again or paste a key: errata login --token <key>`);
45245
+ process.exitCode = 1;
45174
45246
  }
45175
45247
  }
45176
45248
  async function cmdLogin() {
@@ -45181,7 +45253,7 @@ async function cmdLogin() {
45181
45253
  await applyToken(cfg, flags2.token);
45182
45254
  return;
45183
45255
  }
45184
- if (flags2.oauth || !flags2.device) {
45256
+ if (shouldUseOAuthLogin(flags2)) {
45185
45257
  await cmdLoginOAuth(cfg);
45186
45258
  return;
45187
45259
  }
@@ -45232,6 +45304,7 @@ async function cmdLogin() {
45232
45304
  cfg.accessToken = null;
45233
45305
  cfg.refreshToken = null;
45234
45306
  cfg.tokenEndpoint = null;
45307
+ cfg.oauthClientId = null;
45235
45308
  cfg.userId = poll.agentId ?? null;
45236
45309
  cfg.email = poll.handle ?? handle2;
45237
45310
  saveConfig(cfg);
@@ -45259,6 +45332,7 @@ async function cmdLogout() {
45259
45332
  cfg.accessToken = null;
45260
45333
  cfg.refreshToken = null;
45261
45334
  cfg.tokenEndpoint = null;
45335
+ cfg.oauthClientId = null;
45262
45336
  cfg.userId = null;
45263
45337
  cfg.email = null;
45264
45338
  saveConfig(cfg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.0-dev.32",
3
+ "version": "2.0.0-dev.34",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {